Merge branch 'trunk' into e2e/fix-failing-daily-product-variations
This commit is contained in:
commit
0eacfc31cf
|
@ -1,5 +1,13 @@
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 7.5.1 2023-03-21 =
|
||||||
|
|
||||||
|
**WooCommerce**
|
||||||
|
|
||||||
|
* Fix - Fix no enforcing of min/max limits in quantity selector of variable products. [#36871](https://github.com/woocommerce/woocommerce/pull/36871)
|
||||||
|
* Dev - Update column definitions with synonymous types to prevent dbDelta from trying to ALTER them on each install. [#37277](https://github.com/woocommerce/woocommerce/pull/37277)
|
||||||
|
* Update - Update WooCommerce Blocks to 9.6.6. [#37298](https://github.com/woocommerce/woocommerce/pull/37298)
|
||||||
|
|
||||||
= 7.5.0 2023-03-14 =
|
= 7.5.0 2023-03-14 =
|
||||||
|
|
||||||
**WooCommerce**
|
**WooCommerce**
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Adding simple DisplayState wrapper and modifying Collapsible component to allow rendering hidden content.
|
|
@ -7,10 +7,12 @@ import { Icon, chevronDown, chevronUp } from '@wordpress/icons';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
import { DisplayState } from '../display-state';
|
||||||
|
|
||||||
export type CollapsedProps = {
|
export type CollapsedProps = {
|
||||||
initialCollapsed?: boolean;
|
initialCollapsed?: boolean;
|
||||||
toggleText: string;
|
toggleText: string;
|
||||||
|
persistRender?: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
} & React.HTMLAttributes< HTMLDivElement >;
|
} & React.HTMLAttributes< HTMLDivElement >;
|
||||||
|
|
||||||
|
@ -18,9 +20,19 @@ export const CollapsibleContent: React.FC< CollapsedProps > = ( {
|
||||||
initialCollapsed = true,
|
initialCollapsed = true,
|
||||||
toggleText,
|
toggleText,
|
||||||
children,
|
children,
|
||||||
|
persistRender = false,
|
||||||
...props
|
...props
|
||||||
}: CollapsedProps ) => {
|
}: CollapsedProps ) => {
|
||||||
const [ collapsed, setCollapsed ] = useState( initialCollapsed );
|
const [ collapsed, setCollapsed ] = useState( initialCollapsed );
|
||||||
|
|
||||||
|
const getState = () => {
|
||||||
|
if ( ! collapsed ) {
|
||||||
|
return 'visible';
|
||||||
|
}
|
||||||
|
|
||||||
|
return persistRender ? 'visually-hidden' : 'hidden';
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
aria-expanded={ collapsed ? 'false' : 'true' }
|
aria-expanded={ collapsed ? 'false' : 'true' }
|
||||||
|
@ -38,14 +50,14 @@ export const CollapsibleContent: React.FC< CollapsedProps > = ( {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{ ! collapsed && (
|
<DisplayState state={ getState() }>
|
||||||
<div
|
<div
|
||||||
{ ...props }
|
{ ...props }
|
||||||
className="woocommerce-collapsible-content__content"
|
className="woocommerce-collapsible-content__content"
|
||||||
>
|
>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
) }
|
</DisplayState>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { createElement, Fragment } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type DisplayStateProps = {
|
||||||
|
state?: 'visible' | 'visually-hidden' | 'hidden';
|
||||||
|
children: React.ReactNode;
|
||||||
|
} & React.HTMLAttributes< HTMLDivElement >;
|
||||||
|
|
||||||
|
export const DisplayState: React.FC< DisplayStateProps > = ( {
|
||||||
|
state = 'visible',
|
||||||
|
children,
|
||||||
|
} ) => {
|
||||||
|
if ( state === 'visible' ) {
|
||||||
|
return <>{ children }</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( state === 'visually-hidden' ) {
|
||||||
|
return <div style={ { display: 'none' } }>{ children }</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './display-state';
|
|
@ -103,3 +103,4 @@ export {
|
||||||
ProductSectionLayout as __experimentalProductSectionLayout,
|
ProductSectionLayout as __experimentalProductSectionLayout,
|
||||||
ProductFieldSection as __experimentalProductFieldSection,
|
ProductFieldSection as __experimentalProductFieldSection,
|
||||||
} from './product-section-layout';
|
} from './product-section-layout';
|
||||||
|
export { DisplayState } from './display-state';
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Move additional components to @woocommerce/customer-effort-score.
|
|
@ -51,6 +51,7 @@
|
||||||
"@woocommerce/eslint-plugin": "workspace:*",
|
"@woocommerce/eslint-plugin": "workspace:*",
|
||||||
"@woocommerce/internal-style-build": "workspace:*",
|
"@woocommerce/internal-style-build": "workspace:*",
|
||||||
"@woocommerce/navigation": "workspace:*",
|
"@woocommerce/navigation": "workspace:*",
|
||||||
|
"@woocommerce/tracks": "workspace:*",
|
||||||
"@wordpress/browserslist-config": "wp-6.0",
|
"@wordpress/browserslist-config": "wp-6.0",
|
||||||
"concurrently": "^7.0.0",
|
"concurrently": "^7.0.0",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import {
|
|
||||||
CustomerFeedbackModal,
|
|
||||||
STORE_KEY,
|
|
||||||
} from '@woocommerce/customer-effort-score';
|
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
|
||||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
import { createElement } from '@wordpress/element';
|
||||||
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getStoreAgeInWeeks } from './utils';
|
import { CustomerFeedbackModal } from '../';
|
||||||
import { ADMIN_INSTALL_TIMESTAMP_OPTION_NAME } from './constants';
|
import { getStoreAgeInWeeks } from '../../utils';
|
||||||
|
import { STORE_KEY } from '../../store';
|
||||||
|
import { ADMIN_INSTALL_TIMESTAMP_OPTION_NAME } from '../../constants';
|
||||||
|
|
||||||
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
|
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
|
||||||
'woocommerce_ces_product_mvp_ces_action';
|
'woocommerce_ces_product_mvp_ces_action';
|
|
@ -4,17 +4,15 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { compose } from '@wordpress/compose';
|
import { compose } from '@wordpress/compose';
|
||||||
import { withDispatch, withSelect } from '@wordpress/data';
|
import { withDispatch, withSelect } from '@wordpress/data';
|
||||||
import {
|
import { createElement, Fragment } from '@wordpress/element';
|
||||||
QUEUE_OPTION_NAME,
|
|
||||||
STORE_KEY,
|
|
||||||
} from '@woocommerce/customer-effort-score';
|
|
||||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import CustomerEffortScoreTracks from './customer-effort-score-tracks';
|
import { CustomerEffortScoreTracks } from '../';
|
||||||
|
import { QUEUE_OPTION_NAME, STORE_KEY } from '../../store';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps the queue of CES tracks surveys to CustomerEffortScoreTracks
|
* Maps the queue of CES tracks surveys to CustomerEffortScoreTracks
|
||||||
|
@ -27,7 +25,7 @@ import CustomerEffortScoreTracks from './customer-effort-score-tracks';
|
||||||
* @param {boolean} props.resolving Whether the queue is resolving.
|
* @param {boolean} props.resolving Whether the queue is resolving.
|
||||||
* @param {Function} props.clearQueue Sets up clearing of the queue on the next page load.
|
* @param {Function} props.clearQueue Sets up clearing of the queue on the next page load.
|
||||||
*/
|
*/
|
||||||
function CustomerEffortScoreTracksContainer( {
|
function _CustomerEffortScoreTracksContainer( {
|
||||||
queue,
|
queue,
|
||||||
resolving,
|
resolving,
|
||||||
clearQueue,
|
clearQueue,
|
||||||
|
@ -67,7 +65,7 @@ function CustomerEffortScoreTracksContainer( {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomerEffortScoreTracksContainer.propTypes = {
|
_CustomerEffortScoreTracksContainer.propTypes = {
|
||||||
/**
|
/**
|
||||||
* The queue of CES tracks surveys to display.
|
* The queue of CES tracks surveys to display.
|
||||||
*/
|
*/
|
||||||
|
@ -82,7 +80,7 @@ CustomerEffortScoreTracksContainer.propTypes = {
|
||||||
clearQueue: PropTypes.func,
|
clearQueue: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose(
|
export const CustomerEffortScoreTracksContainer = compose(
|
||||||
withSelect( ( select ) => {
|
withSelect( ( select ) => {
|
||||||
const { getCesSurveyQueue, isResolving } = select( STORE_KEY );
|
const { getCesSurveyQueue, isResolving } = select( STORE_KEY );
|
||||||
const queue = getCesSurveyQueue();
|
const queue = getCesSurveyQueue();
|
||||||
|
@ -109,4 +107,4 @@ export default compose(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} )
|
} )
|
||||||
)( CustomerEffortScoreTracksContainer );
|
)( _CustomerEffortScoreTracksContainer );
|
|
@ -1,26 +1,24 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { useState } from '@wordpress/element';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
|
||||||
import {
|
|
||||||
ALLOW_TRACKING_OPTION_NAME,
|
|
||||||
CustomerEffortScore,
|
|
||||||
} from '@woocommerce/customer-effort-score';
|
|
||||||
import { compose } from '@wordpress/compose';
|
import { compose } from '@wordpress/compose';
|
||||||
import { withSelect, withDispatch } from '@wordpress/data';
|
import { withSelect, withDispatch } from '@wordpress/data';
|
||||||
|
import { createElement, useState } from '@wordpress/element';
|
||||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
import { CustomerEffortScore } from '../';
|
||||||
import {
|
import {
|
||||||
SHOWN_FOR_ACTIONS_OPTION_NAME,
|
|
||||||
ADMIN_INSTALL_TIMESTAMP_OPTION_NAME,
|
ADMIN_INSTALL_TIMESTAMP_OPTION_NAME,
|
||||||
} from './constants';
|
ALLOW_TRACKING_OPTION_NAME,
|
||||||
import { getStoreAgeInWeeks } from './utils';
|
SHOWN_FOR_ACTIONS_OPTION_NAME,
|
||||||
|
} from '../../constants';
|
||||||
|
import { getStoreAgeInWeeks } from '../../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A CustomerEffortScore wrapper that uses tracks to track the selected
|
* A CustomerEffortScore wrapper that uses tracks to track the selected
|
||||||
|
@ -43,7 +41,7 @@ import { getStoreAgeInWeeks } from './utils';
|
||||||
* @param {Function} props.updateOptions Function to update options.
|
* @param {Function} props.updateOptions Function to update options.
|
||||||
* @param {Function} props.createNotice Function to create a snackbar.
|
* @param {Function} props.createNotice Function to create a snackbar.
|
||||||
*/
|
*/
|
||||||
function CustomerEffortScoreTracks( {
|
function _CustomerEffortScoreTracks( {
|
||||||
action,
|
action,
|
||||||
trackProps,
|
trackProps,
|
||||||
title,
|
title,
|
||||||
|
@ -176,7 +174,7 @@ function CustomerEffortScoreTracks( {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomerEffortScoreTracks.propTypes = {
|
_CustomerEffortScoreTracks.propTypes = {
|
||||||
/**
|
/**
|
||||||
* The action name sent to Tracks.
|
* The action name sent to Tracks.
|
||||||
*/
|
*/
|
||||||
|
@ -219,7 +217,7 @@ CustomerEffortScoreTracks.propTypes = {
|
||||||
createNotice: PropTypes.func,
|
createNotice: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose(
|
export const CustomerEffortScoreTracks = compose(
|
||||||
withSelect( ( select ) => {
|
withSelect( ( select ) => {
|
||||||
const { getOption, hasFinishedResolution } =
|
const { getOption, hasFinishedResolution } =
|
||||||
select( OPTIONS_STORE_NAME );
|
select( OPTIONS_STORE_NAME );
|
||||||
|
@ -262,4 +260,4 @@ export default compose(
|
||||||
createNotice,
|
createNotice,
|
||||||
};
|
};
|
||||||
} )
|
} )
|
||||||
)( CustomerEffortScoreTracks );
|
)( _CustomerEffortScoreTracks );
|
|
@ -0,0 +1,8 @@
|
||||||
|
export * from './customer-effort-score';
|
||||||
|
export * from './customer-effort-score-modal-container';
|
||||||
|
export * from './customer-effort-score-tracks';
|
||||||
|
export * from './customer-effort-score-tracks-container';
|
||||||
|
export * from './customer-feedback-simple';
|
||||||
|
export * from './customer-feedback-modal';
|
||||||
|
export * from './product-mvp-feedback-modal';
|
||||||
|
export * from './feedback-modal';
|
|
@ -1 +1,7 @@
|
||||||
|
export const ADMIN_INSTALL_TIMESTAMP_OPTION_NAME =
|
||||||
|
'woocommerce_admin_install_timestamp';
|
||||||
|
|
||||||
export const ALLOW_TRACKING_OPTION_NAME = 'woocommerce_allow_tracking';
|
export const ALLOW_TRACKING_OPTION_NAME = 'woocommerce_allow_tracking';
|
||||||
|
|
||||||
|
export const SHOWN_FOR_ACTIONS_OPTION_NAME =
|
||||||
|
'woocommerce_ces_shown_for_actions';
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './use-customer-effort-score-exit-page-tracker';
|
|
@ -1,9 +1,5 @@
|
||||||
export * from './components/customer-effort-score';
|
export * from './components';
|
||||||
export * from './components/customer-feedback-simple';
|
|
||||||
export * from './components/customer-feedback-modal';
|
|
||||||
export * from './components/product-mvp-feedback-modal';
|
|
||||||
export * from './components/feedback-modal';
|
|
||||||
export * from './hooks/use-customer-effort-score-exit-page-tracker';
|
|
||||||
export * from './store';
|
|
||||||
export * from './utils/customer-effort-score-exit-page';
|
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
|
export * from './hooks';
|
||||||
|
export * from './store';
|
||||||
|
export * from './utils';
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './customer-effort-score-exit-page';
|
||||||
|
export * from './get-store-age-in-weeks';
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: fix
|
||||||
|
|
||||||
|
Fix linter errors
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
extends: '../internal-js-tests/babel.config.js',
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add custom validation hook
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add summary block
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Adding Collapsible block with support for flexible rendering.
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"rootDir": "./src",
|
||||||
|
"preset": "../../internal-js-tests/jest.config.js"
|
||||||
|
}
|
|
@ -58,8 +58,15 @@
|
||||||
"react-router-dom": "^6.3.0"
|
"react-router-dom": "^6.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.21.3",
|
||||||
|
"@babel/runtime": "^7.17.2",
|
||||||
|
"@testing-library/jest-dom": "^5.16.2",
|
||||||
"@testing-library/react": "^12.1.3",
|
"@testing-library/react": "^12.1.3",
|
||||||
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"@types/jest": "^27.4.1",
|
||||||
"@types/react": "^17.0.2",
|
"@types/react": "^17.0.2",
|
||||||
|
"@types/testing-library__jest-dom": "^5.14.3",
|
||||||
"@types/wordpress__block-editor": "^7.0.0",
|
"@types/wordpress__block-editor": "^7.0.0",
|
||||||
"@types/wordpress__block-library": "^2.6.1",
|
"@types/wordpress__block-library": "^2.6.1",
|
||||||
"@types/wordpress__blocks": "^11.0.7",
|
"@types/wordpress__blocks": "^11.0.7",
|
||||||
|
@ -91,10 +98,12 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"turbo:build": "pnpm run build:js && pnpm run build:css",
|
"turbo:build": "pnpm run build:js && pnpm run build:css",
|
||||||
|
"turbo:test": "jest --config ./jest.config.json",
|
||||||
"prepare": "composer install",
|
"prepare": "composer install",
|
||||||
"changelog": "composer exec -- changelogger",
|
"changelog": "composer exec -- changelogger",
|
||||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||||
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
|
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
|
||||||
|
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||||
"build:css": "webpack",
|
"build:css": "webpack",
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
|
"apiVersion": 2,
|
||||||
|
"name": "woocommerce/collapsible",
|
||||||
|
"title": "Collapsible",
|
||||||
|
"category": "widgets",
|
||||||
|
"description": "Container with collapsible inner blocks.",
|
||||||
|
"textdomain": "default",
|
||||||
|
"attributes": {
|
||||||
|
"toggleText": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"initialCollapsed": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"persistRender": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports": {
|
||||||
|
"align": false,
|
||||||
|
"html": false,
|
||||||
|
"multiple": true,
|
||||||
|
"reusable": false,
|
||||||
|
"inserter": false,
|
||||||
|
"lock": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { CollapsibleContent } from '@woocommerce/components';
|
||||||
|
import type { BlockAttributes } from '@wordpress/blocks';
|
||||||
|
import { createElement } from '@wordpress/element';
|
||||||
|
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
export function Edit( { attributes }: { attributes: BlockAttributes } ) {
|
||||||
|
const blockProps = useBlockProps();
|
||||||
|
const { toggleText, initialCollapsed, persistRender = true } = attributes;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<CollapsibleContent
|
||||||
|
toggleText={ toggleText }
|
||||||
|
initialCollapsed={ initialCollapsed }
|
||||||
|
persistRender={ persistRender }
|
||||||
|
>
|
||||||
|
<InnerBlocks templateLock="all" />
|
||||||
|
</CollapsibleContent>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { initBlock } from '../../utils';
|
||||||
|
import metadata from './block.json';
|
||||||
|
import { Edit } from './edit';
|
||||||
|
|
||||||
|
const { name } = metadata;
|
||||||
|
|
||||||
|
export { metadata, name };
|
||||||
|
|
||||||
|
export const settings = {
|
||||||
|
example: {},
|
||||||
|
edit: Edit,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const init = () =>
|
||||||
|
initBlock( { name, metadata: metadata as never, settings } );
|
|
@ -14,4 +14,9 @@ export const settings = {
|
||||||
edit: Edit,
|
edit: Edit,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const init = () => initBlock( { name, metadata, settings } );
|
export const init = () =>
|
||||||
|
initBlock( {
|
||||||
|
name,
|
||||||
|
metadata: metadata as never,
|
||||||
|
settings,
|
||||||
|
} );
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||||
|
"apiVersion": 2,
|
||||||
|
"name": "woocommerce/product-summary",
|
||||||
|
"title": "Product summary",
|
||||||
|
"category": "widgets",
|
||||||
|
"description": "The product summary.",
|
||||||
|
"keywords": [ "products", "summary", "excerpt" ],
|
||||||
|
"textdomain": "default",
|
||||||
|
"attributes": {
|
||||||
|
"align": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [ "ltr", "rtl" ]
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports": {
|
||||||
|
"align": false,
|
||||||
|
"html": false,
|
||||||
|
"multiple": false,
|
||||||
|
"reusable": false,
|
||||||
|
"inserter": false,
|
||||||
|
"lock": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import {
|
||||||
|
alignCenter,
|
||||||
|
alignJustify,
|
||||||
|
alignLeft,
|
||||||
|
alignRight,
|
||||||
|
} from '@wordpress/icons';
|
||||||
|
|
||||||
|
export const ALIGNMENT_CONTROLS = [
|
||||||
|
{
|
||||||
|
icon: alignLeft,
|
||||||
|
title: __( 'Align text left', 'woocommerce' ),
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: alignCenter,
|
||||||
|
title: __( 'Align text center', 'woocommerce' ),
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: alignRight,
|
||||||
|
title: __( 'Align text right', 'woocommerce' ),
|
||||||
|
align: 'right',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: alignJustify,
|
||||||
|
title: __( 'Align text justify', 'woocommerce' ),
|
||||||
|
align: 'justify',
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { createElement } from '@wordpress/element';
|
||||||
|
import { BlockEditProps } from '@wordpress/blocks';
|
||||||
|
import { BaseControl } from '@wordpress/components';
|
||||||
|
import { useEntityProp } from '@wordpress/core-data';
|
||||||
|
import uniqueId from 'lodash/uniqueId';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore No types for this exist yet.
|
||||||
|
AlignmentControl,
|
||||||
|
BlockControls,
|
||||||
|
RichText,
|
||||||
|
useBlockProps,
|
||||||
|
} from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { ParagraphRTLControl } from './paragraph-rtl-control';
|
||||||
|
import { SummaryAttributes } from './types';
|
||||||
|
import { ALIGNMENT_CONTROLS } from './constants';
|
||||||
|
|
||||||
|
export function Edit( {
|
||||||
|
attributes,
|
||||||
|
setAttributes,
|
||||||
|
}: BlockEditProps< SummaryAttributes > ) {
|
||||||
|
const { align, direction, label } = attributes;
|
||||||
|
const blockProps = useBlockProps( {
|
||||||
|
style: { direction },
|
||||||
|
} );
|
||||||
|
const id = uniqueId();
|
||||||
|
const [ summary, setSummary ] = useEntityProp< string >(
|
||||||
|
'postType',
|
||||||
|
'product',
|
||||||
|
'short_description'
|
||||||
|
);
|
||||||
|
|
||||||
|
function handleAlignmentChange( value: SummaryAttributes[ 'align' ] ) {
|
||||||
|
setAttributes( { align: value } );
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDirectionChange( value: SummaryAttributes[ 'direction' ] ) {
|
||||||
|
setAttributes( { direction: value } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div { ...blockProps }>
|
||||||
|
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
|
||||||
|
{ /* @ts-ignore No types for this exist yet. */ }
|
||||||
|
<BlockControls group="block">
|
||||||
|
<AlignmentControl
|
||||||
|
alignmentControls={ ALIGNMENT_CONTROLS }
|
||||||
|
value={ align }
|
||||||
|
onChange={ handleAlignmentChange }
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ParagraphRTLControl
|
||||||
|
direction={ direction }
|
||||||
|
onChange={ handleDirectionChange }
|
||||||
|
/>
|
||||||
|
</BlockControls>
|
||||||
|
|
||||||
|
<BaseControl
|
||||||
|
id={ id }
|
||||||
|
label={ label || __( 'Summary', 'woocommerce' ) }
|
||||||
|
>
|
||||||
|
<RichText
|
||||||
|
id={ id }
|
||||||
|
identifier="content"
|
||||||
|
tagName="p"
|
||||||
|
value={ summary }
|
||||||
|
onChange={ setSummary }
|
||||||
|
placeholder={ __(
|
||||||
|
"Summarize this product in 1-2 short sentences. We'll show it at the top of the page.",
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
data-empty={ Boolean( summary ) }
|
||||||
|
className={ classNames( 'components-summary-control', {
|
||||||
|
[ `has-text-align-${ align }` ]: align,
|
||||||
|
} ) }
|
||||||
|
dir={ direction }
|
||||||
|
/>
|
||||||
|
</BaseControl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { BlockConfiguration } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { initBlock } from '../../utils';
|
||||||
|
import blockConfiguration from './block.json';
|
||||||
|
import { Edit } from './edit';
|
||||||
|
import { SummaryAttributes } from './types';
|
||||||
|
|
||||||
|
const { name, ...metadata } =
|
||||||
|
blockConfiguration as BlockConfiguration< SummaryAttributes >;
|
||||||
|
|
||||||
|
export { name, metadata };
|
||||||
|
|
||||||
|
export const settings = {
|
||||||
|
example: {},
|
||||||
|
edit: Edit,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
return initBlock< SummaryAttributes >( {
|
||||||
|
name,
|
||||||
|
metadata,
|
||||||
|
settings,
|
||||||
|
} );
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './paragraph-rtl-control';
|
||||||
|
export * from './types';
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { createElement, Fragment } from '@wordpress/element';
|
||||||
|
import { ToolbarButton } from '@wordpress/components';
|
||||||
|
import { _x, isRTL } from '@wordpress/i18n';
|
||||||
|
import { formatLtr } from '@wordpress/icons';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { ParagraphRTLControlProps } from './types';
|
||||||
|
|
||||||
|
export function ParagraphRTLControl( {
|
||||||
|
direction,
|
||||||
|
onChange,
|
||||||
|
}: ParagraphRTLControlProps ) {
|
||||||
|
function handleClick() {
|
||||||
|
if ( typeof onChange === 'function' ) {
|
||||||
|
onChange( direction === 'ltr' ? undefined : 'ltr' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ isRTL() && (
|
||||||
|
<ToolbarButton
|
||||||
|
icon={ formatLtr }
|
||||||
|
title={ _x(
|
||||||
|
'Left to right',
|
||||||
|
'editor button',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
isActive={ direction === 'ltr' }
|
||||||
|
onClick={ handleClick }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { SummaryAttributes } from '../types';
|
||||||
|
|
||||||
|
export type ParagraphRTLControlProps = Pick<
|
||||||
|
SummaryAttributes,
|
||||||
|
'direction'
|
||||||
|
> & {
|
||||||
|
onChange( direction?: SummaryAttributes[ 'direction' ] ): void;
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
// This alignment class does not exists in
|
||||||
|
// https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/common.scss
|
||||||
|
.has-text-align-justify {
|
||||||
|
/*rtl:ignore*/
|
||||||
|
text-align: justify;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export type SummaryAttributes = {
|
||||||
|
align: 'left' | 'center' | 'right' | 'justify';
|
||||||
|
direction: 'ltr' | 'rtl';
|
||||||
|
label: string;
|
||||||
|
};
|
|
@ -11,8 +11,8 @@ import { createElement } from '@wordpress/element';
|
||||||
*/
|
*/
|
||||||
import { EditProductLinkModal } from '../';
|
import { EditProductLinkModal } from '../';
|
||||||
|
|
||||||
jest.mock( '@woocommerce/product-editor', () => ( {
|
jest.mock( '../../../hooks/use-product-helper', () => ( {
|
||||||
__experimentalUseProductHelper: jest.fn().mockReturnValue( {
|
useProductHelper: jest.fn().mockReturnValue( {
|
||||||
updateProductWithStatus: jest.fn(),
|
updateProductWithStatus: jest.fn(),
|
||||||
isUpdatingDraft: jest.fn(),
|
isUpdatingDraft: jest.fn(),
|
||||||
isUpdatingPublished: jest.fn(),
|
isUpdatingPublished: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
EditorSettings,
|
EditorSettings,
|
||||||
EditorBlockListSettings,
|
EditorBlockListSettings,
|
||||||
} from '@wordpress/block-editor';
|
} from '@wordpress/block-editor';
|
||||||
import { SlotFillProvider } from '@wordpress/components';
|
import { Popover, SlotFillProvider } from '@wordpress/components';
|
||||||
import { Product } from '@woocommerce/data';
|
import { Product } from '@woocommerce/data';
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore No types for this exist yet.
|
// @ts-ignore No types for this exist yet.
|
||||||
|
@ -60,6 +60,8 @@ export function Editor( { product, settings }: EditorProps ) {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Popover.Slot />
|
||||||
</SlotFillProvider>
|
</SlotFillProvider>
|
||||||
</ShortcutProvider>
|
</ShortcutProvider>
|
||||||
</EntityProvider>
|
</EntityProvider>
|
||||||
|
|
|
@ -7,14 +7,18 @@ import { registerCoreBlocks } from '@wordpress/block-library';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { init as initName } from '../details-name-block';
|
import { init as initName } from '../details-name-block';
|
||||||
|
import { init as initSummary } from '../details-summary-block';
|
||||||
import { init as initSection } from '../section';
|
import { init as initSection } from '../section';
|
||||||
import { init as initTab } from '../tab';
|
import { init as initTab } from '../tab';
|
||||||
import { init as initPricing } from '../pricing-block';
|
import { init as initPricing } from '../pricing-block';
|
||||||
|
import { init as initCollapsible } from '../collapsible-block';
|
||||||
|
|
||||||
export const initBlocks = () => {
|
export const initBlocks = () => {
|
||||||
registerCoreBlocks();
|
registerCoreBlocks();
|
||||||
initName();
|
initName();
|
||||||
|
initSummary();
|
||||||
initSection();
|
initSection();
|
||||||
initTab();
|
initTab();
|
||||||
initPricing();
|
initPricing();
|
||||||
|
initCollapsible();
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,4 +14,9 @@ export const settings = {
|
||||||
edit: Edit,
|
edit: Edit,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const init = () => initBlock( { name, metadata, settings } );
|
export const init = () =>
|
||||||
|
initBlock( {
|
||||||
|
name,
|
||||||
|
metadata: metadata as never,
|
||||||
|
settings,
|
||||||
|
} );
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# useValidation
|
||||||
|
|
||||||
|
This custom hook uses the helper functions `const { lockPostSaving, unlockPostSaving } = useDispatch( 'core/editor' );` to lock/unlock the current editing product before saving it.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Syncronous validation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useCallback } from '@wordpress/element';
|
||||||
|
import { useValidation } from '@woocommerce/product-editor';
|
||||||
|
|
||||||
|
const product = ...;
|
||||||
|
|
||||||
|
const validateTitle = useCallback( (): boolean => {
|
||||||
|
if ( product.title.length < 2 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, [ product.title ] );
|
||||||
|
|
||||||
|
const isTitleValid = useValidation( 'product/title', validateTitle );
|
||||||
|
```
|
||||||
|
|
||||||
|
Asyncronous validation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { useCallback } from '@wordpress/element';
|
||||||
|
import { useValidation } from '@woocommerce/product-editor';
|
||||||
|
|
||||||
|
const product = ...;
|
||||||
|
|
||||||
|
const validateSlug = useCallback( async (): Promise< boolean > => {
|
||||||
|
return fetch( `.../validate-slug?slug=${ product.slug }` )
|
||||||
|
.then( ( response ) => response.json() )
|
||||||
|
.then( ( { isValid } ) => isValid )
|
||||||
|
.catch( () => false );
|
||||||
|
}, [ product.slug ] );
|
||||||
|
|
||||||
|
const isSlugValid = useValidation( 'product/slug', validateSlug );
|
||||||
|
```
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './use-validation';
|
|
@ -0,0 +1,95 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { renderHook } from '@testing-library/react-hooks';
|
||||||
|
import { useDispatch } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { useValidation } from '../use-validation';
|
||||||
|
|
||||||
|
jest.mock( '@wordpress/data', () => ( {
|
||||||
|
useDispatch: jest.fn(),
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
describe( 'useValidation', () => {
|
||||||
|
const useDispatchMock = useDispatch as jest.Mock;
|
||||||
|
const lockPostSaving = jest.fn();
|
||||||
|
const unlockPostSaving = jest.fn();
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
useDispatchMock.mockReturnValue( {
|
||||||
|
lockPostSaving,
|
||||||
|
unlockPostSaving,
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
afterEach( () => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
} );
|
||||||
|
|
||||||
|
describe( 'sync', () => {
|
||||||
|
it( 'should lock the editor if validate returns false', async () => {
|
||||||
|
const { result, waitForNextUpdate } = renderHook( () =>
|
||||||
|
useValidation( 'product/name', () => false )
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForNextUpdate();
|
||||||
|
|
||||||
|
expect( result.current ).toBeFalsy();
|
||||||
|
expect( lockPostSaving ).toHaveBeenCalled();
|
||||||
|
expect( unlockPostSaving ).not.toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should unlock the editor if validate returns true', async () => {
|
||||||
|
const { result, waitForNextUpdate } = renderHook( () =>
|
||||||
|
useValidation( 'product/name', () => true )
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForNextUpdate();
|
||||||
|
|
||||||
|
expect( result.current ).toBeTruthy();
|
||||||
|
expect( lockPostSaving ).not.toHaveBeenCalled();
|
||||||
|
expect( unlockPostSaving ).toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
describe( 'async', () => {
|
||||||
|
it( 'should lock the editor if validate resolves false', async () => {
|
||||||
|
const { result, waitForNextUpdate } = renderHook( () =>
|
||||||
|
useValidation( 'product/name', () => Promise.resolve( false ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForNextUpdate();
|
||||||
|
|
||||||
|
expect( result.current ).toBeFalsy();
|
||||||
|
expect( lockPostSaving ).toHaveBeenCalled();
|
||||||
|
expect( unlockPostSaving ).not.toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should lock the editor if validate rejects', async () => {
|
||||||
|
const { result, waitForNextUpdate } = renderHook( () =>
|
||||||
|
useValidation( 'product/name', () => Promise.reject() )
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForNextUpdate();
|
||||||
|
|
||||||
|
expect( result.current ).toBeFalsy();
|
||||||
|
expect( lockPostSaving ).toHaveBeenCalled();
|
||||||
|
expect( unlockPostSaving ).not.toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should unlock the editor if validate resolves true', async () => {
|
||||||
|
const { result, waitForNextUpdate } = renderHook( () =>
|
||||||
|
useValidation( 'product/name', () => Promise.resolve( true ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForNextUpdate();
|
||||||
|
|
||||||
|
expect( result.current ).toBeTruthy();
|
||||||
|
expect( lockPostSaving ).not.toHaveBeenCalled();
|
||||||
|
expect( unlockPostSaving ).toHaveBeenCalled();
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useDispatch } from '@wordpress/data';
|
||||||
|
import { useEffect, useState } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that product saving is locked.
|
||||||
|
*
|
||||||
|
* @param lockName The namespace used to lock the product saving if validation fails.
|
||||||
|
* @param validate The validator function.
|
||||||
|
*/
|
||||||
|
export function useValidation(
|
||||||
|
lockName: string,
|
||||||
|
validate: () => boolean | Promise< boolean >
|
||||||
|
): boolean | undefined {
|
||||||
|
const [ isValid, setIsValid ] = useState< boolean | undefined >();
|
||||||
|
const { lockPostSaving, unlockPostSaving } = useDispatch( 'core/editor' );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
let validationResponse = validate();
|
||||||
|
|
||||||
|
if ( typeof validationResponse === 'boolean' ) {
|
||||||
|
validationResponse = Promise.resolve( validationResponse );
|
||||||
|
}
|
||||||
|
|
||||||
|
validationResponse
|
||||||
|
.then( ( isValidationValid ) => {
|
||||||
|
if ( isValidationValid ) {
|
||||||
|
unlockPostSaving( lockName );
|
||||||
|
} else {
|
||||||
|
lockPostSaving( lockName );
|
||||||
|
}
|
||||||
|
setIsValid( isValidationValid );
|
||||||
|
} )
|
||||||
|
.catch( () => {
|
||||||
|
lockPostSaving( lockName );
|
||||||
|
setIsValid( false );
|
||||||
|
} );
|
||||||
|
}, [ lockName, validate, lockPostSaving, unlockPostSaving ] );
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
|
@ -8,3 +8,4 @@
|
||||||
@import 'components/section/style.scss';
|
@import 'components/section/style.scss';
|
||||||
@import 'components/tab/style.scss';
|
@import 'components/tab/style.scss';
|
||||||
@import 'components/tabs/style.scss';
|
@import 'components/tabs/style.scss';
|
||||||
|
@import 'components/details-summary-block/style.scss';
|
||||||
|
|
|
@ -1,26 +1,31 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { BlockConfiguration, registerBlockType } from '@wordpress/blocks';
|
import {
|
||||||
|
Block,
|
||||||
|
BlockConfiguration,
|
||||||
|
registerBlockType,
|
||||||
|
} from '@wordpress/blocks';
|
||||||
|
|
||||||
interface BlockRepresentation {
|
interface BlockRepresentation< T extends Record< string, object > > {
|
||||||
name: string;
|
name?: string;
|
||||||
metadata: BlockConfiguration;
|
metadata: BlockConfiguration< T >;
|
||||||
settings: Partial< BlockConfiguration >;
|
settings: Partial< BlockConfiguration< T > >;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to register an individual block.
|
* Function to register an individual block.
|
||||||
*
|
*
|
||||||
* @param {Object} block The block to be registered.
|
* @param block The block to be registered.
|
||||||
*
|
* @return The block, if it has been successfully registered; otherwise `undefined`.
|
||||||
* @return {?WPBlockType} The block, if it has been successfully registered;
|
|
||||||
* otherwise `undefined`.
|
|
||||||
*/
|
*/
|
||||||
export const initBlock = ( block: BlockRepresentation ) => {
|
export function initBlock<
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
T extends Record< string, any > = Record< string, any >
|
||||||
|
>( block: BlockRepresentation< T > ): Block< T > | undefined {
|
||||||
if ( ! block ) {
|
if ( ! block ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { metadata, settings, name } = block;
|
const { metadata, settings, name } = block;
|
||||||
return registerBlockType( { name, ...metadata }, settings );
|
return registerBlockType< T >( { name, ...metadata }, settings );
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export const SHOWN_FOR_ACTIONS_OPTION_NAME =
|
|
||||||
'woocommerce_ces_shown_for_actions';
|
|
||||||
export const ADMIN_INSTALL_TIMESTAMP_OPTION_NAME =
|
|
||||||
'woocommerce_admin_install_timestamp';
|
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as CustomerEffortScoreTracks } from './customer-effort-score-tracks';
|
|
||||||
export { default as CustomerEffortScoreTracksContainer } from './customer-effort-score-tracks-container';
|
|
||||||
export * from './customer-effort-score-modal-container.tsx';
|
|
|
@ -9,6 +9,7 @@ import { WooFooterItem } from '@woocommerce/admin-layout';
|
||||||
import { Pill } from '@woocommerce/components';
|
import { Pill } from '@woocommerce/components';
|
||||||
import {
|
import {
|
||||||
ALLOW_TRACKING_OPTION_NAME,
|
ALLOW_TRACKING_OPTION_NAME,
|
||||||
|
SHOWN_FOR_ACTIONS_OPTION_NAME,
|
||||||
STORE_KEY,
|
STORE_KEY,
|
||||||
} from '@woocommerce/customer-effort-score';
|
} from '@woocommerce/customer-effort-score';
|
||||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
@ -17,7 +18,6 @@ import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './product-mvp-ces-footer.scss';
|
import './product-mvp-ces-footer.scss';
|
||||||
import { SHOWN_FOR_ACTIONS_OPTION_NAME } from './constants';
|
|
||||||
|
|
||||||
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
|
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
|
||||||
'woocommerce_ces_product_mvp_ces_action';
|
'woocommerce_ces_product_mvp_ces_action';
|
||||||
|
|
|
@ -9,9 +9,3 @@ export const WELCOME_MODAL_DISMISSED_OPTION_NAME =
|
||||||
*/
|
*/
|
||||||
export const WELCOME_FROM_CALYPSO_MODAL_DISMISSED_OPTION_NAME =
|
export const WELCOME_FROM_CALYPSO_MODAL_DISMISSED_OPTION_NAME =
|
||||||
'woocommerce_welcome_from_calypso_modal_dismissed';
|
'woocommerce_welcome_from_calypso_modal_dismissed';
|
||||||
|
|
||||||
/**
|
|
||||||
* WooCommerce Admin installation timestamp option name.
|
|
||||||
*/
|
|
||||||
export const WOOCOMMERCE_ADMIN_INSTALL_TIMESTAMP_OPTION_NAME =
|
|
||||||
'woocommerce_admin_install_timestamp';
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import '@wordpress/notices';
|
import '@wordpress/notices';
|
||||||
import { render } from '@wordpress/element';
|
import { render } from '@wordpress/element';
|
||||||
|
import { CustomerEffortScoreTracksContainer } from '@woocommerce/customer-effort-score';
|
||||||
import {
|
import {
|
||||||
withCurrentUserHydration,
|
withCurrentUserHydration,
|
||||||
withSettingsHydration,
|
withSettingsHydration,
|
||||||
|
@ -14,7 +15,6 @@ import {
|
||||||
import './stylesheets/_index.scss';
|
import './stylesheets/_index.scss';
|
||||||
import { getAdminSetting } from '~/utils/admin-settings';
|
import { getAdminSetting } from '~/utils/admin-settings';
|
||||||
import { PageLayout, EmbedLayout, PrimaryLayout as NoticeArea } from './layout';
|
import { PageLayout, EmbedLayout, PrimaryLayout as NoticeArea } from './layout';
|
||||||
import { CustomerEffortScoreTracksContainer } from './customer-effort-score-tracks';
|
|
||||||
import { EmbeddedBodyLayout } from './embedded-body-layout';
|
import { EmbeddedBodyLayout } from './embedded-body-layout';
|
||||||
import { WcAdminPaymentsGatewaysBannerSlot } from './payments/payments-settings-banner-slotfill';
|
import { WcAdminPaymentsGatewaysBannerSlot } from './payments/payments-settings-banner-slotfill';
|
||||||
import { WcAdminConflictErrorSlot } from './settings/conflict-error-slotfill.js';
|
import { WcAdminConflictErrorSlot } from './settings/conflict-error-slotfill.js';
|
||||||
|
|
|
@ -17,7 +17,10 @@ import { Children, cloneElement } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { get, isFunction, identity, memoize } from 'lodash';
|
import { get, isFunction, identity, memoize } from 'lodash';
|
||||||
import { parse } from 'qs';
|
import { parse } from 'qs';
|
||||||
import { triggerExitPageCesSurvey } from '@woocommerce/customer-effort-score';
|
import {
|
||||||
|
CustomerEffortScoreModalContainer,
|
||||||
|
triggerExitPageCesSurvey,
|
||||||
|
} from '@woocommerce/customer-effort-score';
|
||||||
import { getHistory, getQuery } from '@woocommerce/navigation';
|
import { getHistory, getQuery } from '@woocommerce/navigation';
|
||||||
import {
|
import {
|
||||||
PLUGINS_STORE_NAME,
|
PLUGINS_STORE_NAME,
|
||||||
|
@ -38,7 +41,6 @@ import { Header } from '../header';
|
||||||
import { Footer } from './footer';
|
import { Footer } from './footer';
|
||||||
import Notices from './notices';
|
import Notices from './notices';
|
||||||
import TransientNotices from './transient-notices';
|
import TransientNotices from './transient-notices';
|
||||||
import { CustomerEffortScoreModalContainer } from '../customer-effort-score-tracks';
|
|
||||||
import { getAdminSetting } from '~/utils/admin-settings';
|
import { getAdminSetting } from '~/utils/admin-settings';
|
||||||
import '~/activity-panel';
|
import '~/activity-panel';
|
||||||
import '~/mobile-banner';
|
import '~/mobile-banner';
|
||||||
|
|
|
@ -19,6 +19,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.components-summary-control {
|
||||||
|
width: 100%;
|
||||||
|
min-height: calc($gap-larger * 3);
|
||||||
|
background-color: $white;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #757575;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: $gap-smaller;
|
||||||
|
margin: 0;
|
||||||
|
appearance: textarea;
|
||||||
|
resize: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color-darker-10, --wp-admin-theme-color);
|
||||||
|
border-color: var(--wp-admin-theme-color-darker-10, --wp-admin-theme-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.woocommerce-product-form {
|
.woocommerce-product-form {
|
||||||
&__custom-label-input {
|
&__custom-label-input {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -10,8 +10,11 @@ import { OPTIONS_STORE_NAME, WCDataSelector, WEEK } from '@woocommerce/data';
|
||||||
import { Button, Card, CardHeader } from '@wordpress/components';
|
import { Button, Card, CardHeader } from '@wordpress/components';
|
||||||
import { Text } from '@woocommerce/experimental';
|
import { Text } from '@woocommerce/experimental';
|
||||||
import {
|
import {
|
||||||
|
ADMIN_INSTALL_TIMESTAMP_OPTION_NAME,
|
||||||
|
ALLOW_TRACKING_OPTION_NAME,
|
||||||
CustomerFeedbackModal,
|
CustomerFeedbackModal,
|
||||||
CustomerFeedbackSimple,
|
CustomerFeedbackSimple,
|
||||||
|
SHOWN_FOR_ACTIONS_OPTION_NAME,
|
||||||
} from '@woocommerce/customer-effort-score';
|
} from '@woocommerce/customer-effort-score';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
@ -27,11 +30,7 @@ type TaskListCompletedHeaderProps = {
|
||||||
customerEffortScore: boolean;
|
customerEffortScore: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ADMIN_INSTALL_TIMESTAMP_OPTION_NAME =
|
|
||||||
'woocommerce_admin_install_timestamp';
|
|
||||||
const SHOWN_FOR_ACTIONS_OPTION_NAME = 'woocommerce_ces_shown_for_actions';
|
|
||||||
const CUSTOMER_EFFORT_SCORE_ACTION = 'store_setup';
|
const CUSTOMER_EFFORT_SCORE_ACTION = 'store_setup';
|
||||||
const ALLOW_TRACKING_OPTION_NAME = 'woocommerce_allow_tracking';
|
|
||||||
|
|
||||||
function getStoreAgeInWeeks( adminInstallTimestamp: number ) {
|
function getStoreAgeInWeeks( adminInstallTimestamp: number ) {
|
||||||
if ( adminInstallTimestamp === 0 ) {
|
if ( adminInstallTimestamp === 0 ) {
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Allow sorting by menu_order in products widget.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: fix
|
|
||||||
|
|
||||||
Fix unit test snapshots due to a dependency version change
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add wp-json/wc-admin/shipping-partner-suggestions API endpoint
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: enhancement
|
|
||||||
|
|
||||||
Add the support for the C&C Blocks in declaring compatibility feature
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Add existing global attribute layout #36944
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Create editor skeleton on add/edit product pages
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: tweak
|
|
||||||
|
|
||||||
Add productId dependency when getting the product by id in ProductPage
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: update
|
|
||||||
|
|
||||||
Add tabs and sections placeholders in product blocks template
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: update
|
|
||||||
|
|
||||||
Update product template by adding the list price and sale price blocks.
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add summary block
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add productBlockEditorSettings script to be used for the Product Block Editor.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add new feature flag for the product edit blocks experience
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Add @woocommerce/admin-layout package.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add an encoding selector to the product importer
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Creating product entity in auto-draft status, and adding support for retrieving preexisting products.
|
|
|
@ -1,5 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: add
|
|
||||||
Comment: Perf test not included in release
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add marketplace suggestions and multichannel marketing information to WC Tracker.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: update
|
|
||||||
|
|
||||||
Update template of product type to include product name block.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add support for new countries in WCPay
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Initial e2e tests for new product editor.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add a cache for orders, to use when custom order tables are enabled
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Added images support for the payment recommendations transaction processors
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: tweak
|
|
||||||
|
|
||||||
Add Tracks events for product inventory tab interactions.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: tweak
|
|
||||||
|
|
||||||
Add tracking for local pickup method in Checkout
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Make WC_Order::get_tax_location accessible publicly through a wrapper function.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Show "Stock status" as a collection of radio buttons
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Set quantity value when stock tracking is enabled
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Show a message for variable products
|
|
|
@ -1,5 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: dev
|
|
||||||
Comment: This is just a dev maintenance, removing duplicated code.
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Sync @wordpress package versions via syncpack.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Set up React Fast Refresh in woocommerce-admin
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Fix lint issues
|
|
|
@ -1,5 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: dev
|
|
||||||
Comment: Use React Fast Refresh for WooCommerce Admin "start:hot" command only; fix empty page issue with "start" command when SCRIPT_DEBUG is set to false.
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Fix the value of `UPDATE_WC` environment variable in the daily k6 performance tests.
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Update OBW end to end test as WC Pay supports Malta now
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: dev
|
|
||||||
|
|
||||||
Support E2E testing of draft releases.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: update
|
|
||||||
|
|
||||||
Updates automated release testing workflow to use Playwright
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add introduction banner to multichannel marketing page.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add Campaigns card into Multichannel Marketing page.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Add "Create a new campaign" modal in Campaigns card in Multichannel Marketing page.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: fix
|
|
||||||
|
|
||||||
Fix React rendering falsy value in marketing page.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: fix
|
|
||||||
|
|
||||||
Fix WP data resolution (`invalidateResolution`) not working with WP 5.9 in marketing page.
|
|
|
@ -1,5 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: fix
|
|
||||||
Comment: Make Reviews table CSS match other list tables.
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: patch
|
|
||||||
Type: fix
|
|
||||||
|
|
||||||
Fix incorrect VAT exempt behaviour on shop page when prices are exclusive of tax.
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: update
|
|
||||||
|
|
||||||
Update the date modified field for an order when a refund for it is successfully processed.
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue