Merge branch 'master' into fix/749
This commit is contained in:
commit
16d5265aed
|
@ -6,5 +6,5 @@ _Replace this with a good description of your changes & reasoning._
|
||||||
|
|
||||||
### Detailed test instructions:
|
### Detailed test instructions:
|
||||||
|
|
||||||
- Ex: Open page `url`
|
- Ex: Open page `url`
|
||||||
- Click XYZ…
|
- Click XYZ…
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"at-rule-no-unknown": null,
|
"at-rule-no-unknown": null,
|
||||||
"comment-empty-line-before": null,
|
"comment-empty-line-before": null,
|
||||||
"declaration-block-no-duplicate-properties": null,
|
"declaration-block-no-duplicate-properties": null,
|
||||||
|
"declaration-colon-newline-after": null,
|
||||||
"declaration-property-unit-whitelist": null,
|
"declaration-property-unit-whitelist": null,
|
||||||
"font-weight-notation": null,
|
"font-weight-notation": null,
|
||||||
"max-line-length": null,
|
"max-line-length": null,
|
||||||
|
@ -12,6 +13,8 @@
|
||||||
"no-duplicate-selectors": null,
|
"no-duplicate-selectors": null,
|
||||||
"rule-empty-line-before": null,
|
"rule-empty-line-before": null,
|
||||||
"selector-class-pattern": null,
|
"selector-class-pattern": null,
|
||||||
"value-keyword-case": null
|
"string-quotes": "single",
|
||||||
|
"value-keyword-case": null,
|
||||||
|
"value-list-comma-newline-after": null
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,33 +1,36 @@
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
||||||
language: php
|
language: php
|
||||||
php:
|
|
||||||
- 7.1
|
|
||||||
|
|
||||||
env:
|
matrix:
|
||||||
- WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1 WP_CORE_DIR=/tmp/wordpress NODE_RELEASE=8.x
|
include:
|
||||||
|
- name: "PHP 7.2 unit tests, PHP Coding standards check and JS tests"
|
||||||
|
php: 7.2
|
||||||
|
env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress NODE_RELEASE=8.x RUN_PHPCS=1 RUN_JS=1
|
||||||
|
- name: "PHP 7.1 unit tests"
|
||||||
|
php: 7.1
|
||||||
|
env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress NODE_RELEASE=8.x
|
||||||
|
- name: "PHP 7.0 unit tests"
|
||||||
|
php: 7.0
|
||||||
|
env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress NODE_RELEASE=8.x
|
||||||
|
- name: "PHP 5.6 unit tests"
|
||||||
|
php: 5.6
|
||||||
|
env: WP_VERSION=latest WP_MULTISITE=0 WP_CORE_DIR=/tmp/wordpress NODE_RELEASE=8.x
|
||||||
|
|
||||||
before_script:
|
|
||||||
- phpenv config-rm xdebug.ini
|
|
||||||
- export PATH="$HOME/.composer/vendor/bin:$PATH"
|
|
||||||
- bash bin/install-wp-tests.sh wc_admin_test root '' localhost $WP_VERSION
|
|
||||||
- bash bin/travis.sh before
|
|
||||||
- sudo rm -rf ~/.nvm
|
|
||||||
- curl -sL "https://deb.nodesource.com/setup_${NODE_RELEASE}" | sudo -E bash -
|
|
||||||
- sudo apt-get install -y nodejs
|
|
||||||
- node --version
|
|
||||||
- npm --version
|
|
||||||
|
|
||||||
|
|
||||||
install:
|
|
||||||
- npm install
|
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- "8"
|
- "8"
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- phpenv config-rm xdebug.ini
|
||||||
|
- export PATH="$WP_CORE_DIR/wp-content/plugins/wc-admin/vendor/bin:$PATH"
|
||||||
|
- bash bin/install-wp-tests.sh wc_admin_test root '' localhost $WP_VERSION
|
||||||
|
- bash bin/travis.sh before
|
||||||
|
- node --version
|
||||||
|
- npm --version
|
||||||
|
- timedatectl
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- npm run lint
|
- bash bin/js_lint_test.sh
|
||||||
- npm run build
|
|
||||||
- npm test
|
|
||||||
- bash bin/phpunit.sh
|
- bash bin/phpunit.sh
|
||||||
- bash bin/phpcs.sh
|
- bash bin/phpcs.sh
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Contributing to WooCommerce Admin
|
||||||
|
|
||||||
|
Hi! Thank you for your interest in contributing to WooCommerce Admin. We appreciate it.
|
||||||
|
|
||||||
|
There are many ways to contribute – reporting bugs, feature suggestions, and fixing bugs.
|
||||||
|
|
||||||
|
## Reporting Bugs, Asking Questions, Sending Suggestions
|
||||||
|
|
||||||
|
Open [a GitHub issue](https://github.com/woocommerce/wc-admin/issues/new/choose), that's all. If you have write access, add any appropriate labels.
|
||||||
|
|
||||||
|
If you're filing a bug, specific steps to reproduce are always helpful. Please include what you expected to see and what happened instead.
|
||||||
|
|
||||||
|
## We're Here To Help
|
||||||
|
|
||||||
|
We encourage you to ask for help. We want your first experience with WooCommerce Admin to be a good one, so don't be shy. If you're wondering why something is the way it is, or how a decision was made, you can tag issues with [Type] Question or prefix them with “Question:”
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
WooCommerce Admin is licensed under [GNU General Public License v2 (or later)](/LICENSE.md).
|
||||||
|
|
||||||
|
All materials contributed should be compatible with the GPLv2. This means that if you own the material, you agree to license it under the GPLv2 license. If you are contributing code that is not your own, such as adding a component from another Open Source project, or adding an `npm` package, you need to make sure you follow these steps:
|
||||||
|
|
||||||
|
1. Check that the code has a license. If you can't find one, you can try to contact the original author and get permission to use, or ask them to release under a compatible Open Source license.
|
||||||
|
2. Check the license is compatible with [GPLv2](http://www.gnu.org/licenses/license-list.en.html#GPLCompatibleLicenses), note that the Apache 2.0 license is *not* compatible.
|
|
@ -20,6 +20,7 @@ After cloning the repo, install dependencies with `npm install`. Now you can bui
|
||||||
|
|
||||||
- `npm run build` : Build a production version
|
- `npm run build` : Build a production version
|
||||||
- `npm start` : Build a development version, watch files for changes
|
- `npm start` : Build a development version, watch files for changes
|
||||||
|
- `npm run build:release` : Build a WordPress plugin ZIP file (`wc-admin.zip` will be created in the repository root)
|
||||||
|
|
||||||
There are also some helper scripts:
|
There are also some helper scripts:
|
||||||
|
|
||||||
|
@ -29,3 +30,7 @@ There are also some helper scripts:
|
||||||
## Privacy
|
## Privacy
|
||||||
|
|
||||||
If you have enabled WooCommerce usage tracking ( option `woocommerce_allow_tracking` ) then, in addition to the tracking described in https://woocommerce.com/usage-tracking/, this plugin also sends information about the actions that site administrators perform to Automattic - see https://automattic.com/privacy/#information-we-collect-automatically for more information.
|
If you have enabled WooCommerce usage tracking ( option `woocommerce_allow_tracking` ) then, in addition to the tracking described in https://woocommerce.com/usage-tracking/, this plugin also sends information about the actions that site administrators perform to Automattic - see https://automattic.com/privacy/#information-we-collect-automatically for more information.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
There are many ways to contribute – reporting bugs, feature suggestions and fixing bugs. For full details, please see [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit if any command fails.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Change to the expected directory.
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Enable nicer messaging for build status.
|
||||||
|
BLUE_BOLD='\033[1;34m';
|
||||||
|
GREEN_BOLD='\033[1;32m';
|
||||||
|
RED_BOLD='\033[1;31m';
|
||||||
|
YELLOW_BOLD='\033[1;33m';
|
||||||
|
COLOR_RESET='\033[0m';
|
||||||
|
error () {
|
||||||
|
echo -e "\n${RED_BOLD}$1${COLOR_RESET}\n"
|
||||||
|
}
|
||||||
|
status () {
|
||||||
|
echo -e "\n${BLUE_BOLD}$1${COLOR_RESET}\n"
|
||||||
|
}
|
||||||
|
success () {
|
||||||
|
echo -e "\n${GREEN_BOLD}$1${COLOR_RESET}\n"
|
||||||
|
}
|
||||||
|
warning () {
|
||||||
|
echo -e "\n${YELLOW_BOLD}$1${COLOR_RESET}\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
status "💃 Time to release WooCommerce Admin 🕺"
|
||||||
|
|
||||||
|
# Make sure there are no changes in the working tree. Release builds should be
|
||||||
|
# traceable to a particular commit and reliably reproducible. (This is not
|
||||||
|
# totally true at the moment because we download nightly vendor scripts).
|
||||||
|
changed=
|
||||||
|
if ! git diff --exit-code > /dev/null; then
|
||||||
|
changed="file(s) modified"
|
||||||
|
elif ! git diff --cached --exit-code > /dev/null; then
|
||||||
|
changed="file(s) staged"
|
||||||
|
fi
|
||||||
|
if [ ! -z "$changed" ]; then
|
||||||
|
git status
|
||||||
|
error "ERROR: Cannot build plugin zip with dirty working tree. ☝️
|
||||||
|
Commit your changes and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do a dry run of the repository reset. Prompting the user for a list of all
|
||||||
|
# files that will be removed should prevent them from losing important files!
|
||||||
|
status "Resetting the repository to pristine condition. ✨"
|
||||||
|
git clean -xdf --dry-run
|
||||||
|
warning "🚨 About to delete everything above! Is this okay? 🚨"
|
||||||
|
echo -n "[y]es/[N]o: "
|
||||||
|
read answer
|
||||||
|
if [ "$answer" != "${answer#[Yy]}" ]; then
|
||||||
|
# Remove ignored files to reset repository to pristine condition. Previous
|
||||||
|
# test ensures that changed files abort the plugin build.
|
||||||
|
status "Cleaning working directory... 🛀"
|
||||||
|
git clean -xdf
|
||||||
|
else
|
||||||
|
error "Fair enough; aborting. Tidy up your repo and try again. 🙂"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the build.
|
||||||
|
status "Generating build... 👷♀️"
|
||||||
|
npm run build
|
||||||
|
npm run docs
|
||||||
|
|
||||||
|
build_files=$(ls dist/*/*.{js,css})
|
||||||
|
|
||||||
|
# Generate the plugin zip file.
|
||||||
|
status "Creating archive... 🎁"
|
||||||
|
zip -r wc-admin.zip \
|
||||||
|
wc-admin.php \
|
||||||
|
lib/*.php \
|
||||||
|
includes/*.php \
|
||||||
|
includes/**/*.php \
|
||||||
|
images/* \
|
||||||
|
$build_files \
|
||||||
|
languages/wc-admin.pot \
|
||||||
|
languages/wc-admin.php \
|
||||||
|
README.md
|
||||||
|
|
||||||
|
success "Done. You've built WooCommerce Admin! 🎉 "
|
|
@ -13,6 +13,7 @@ const { parse, resolver } = require( 'react-docgen' );
|
||||||
const { getDescription, getProps, getTitle } = require( './lib/formatting' );
|
const { getDescription, getProps, getTitle } = require( './lib/formatting' );
|
||||||
const {
|
const {
|
||||||
COMPONENTS_FOLDER,
|
COMPONENTS_FOLDER,
|
||||||
|
PACKAGES_FOLDER,
|
||||||
deleteExistingDocs,
|
deleteExistingDocs,
|
||||||
getExportedFileList,
|
getExportedFileList,
|
||||||
getMdFileName,
|
getMdFileName,
|
||||||
|
@ -20,13 +21,14 @@ const {
|
||||||
writeTableOfContents,
|
writeTableOfContents,
|
||||||
} = require( './lib/file-system' );
|
} = require( './lib/file-system' );
|
||||||
|
|
||||||
const filePath = path.resolve( COMPONENTS_FOLDER, 'index.js' );
|
|
||||||
|
|
||||||
// Start by wiping the existing docs. **Change this if we end up manually editing docs**
|
// Start by wiping the existing docs. **Change this if we end up manually editing docs**
|
||||||
deleteExistingDocs();
|
deleteExistingDocs();
|
||||||
|
|
||||||
// Read components file to get a list of exported files, convert that to a list of absolute paths to public components.
|
// Read components file to get a list of exported files, convert that to a list of absolute paths to public components.
|
||||||
const files = getRealFilePaths( getExportedFileList( filePath ) );
|
const files = [
|
||||||
|
...getRealFilePaths( getExportedFileList( path.resolve( COMPONENTS_FOLDER, 'index.js' ) ) ),
|
||||||
|
...getRealFilePaths( getExportedFileList( path.resolve( PACKAGES_FOLDER, 'index.js' ) ), PACKAGES_FOLDER ),
|
||||||
|
];
|
||||||
|
|
||||||
// Build the documentation by reading each file.
|
// Build the documentation by reading each file.
|
||||||
files.forEach( file => {
|
files.forEach( file => {
|
||||||
|
|
|
@ -15,6 +15,7 @@ const { namedTypes } = types;
|
||||||
const { camelCaseDash } = require( './formatting' );
|
const { camelCaseDash } = require( './formatting' );
|
||||||
|
|
||||||
const COMPONENTS_FOLDER = path.resolve( __dirname, '../../../client/components/' );
|
const COMPONENTS_FOLDER = path.resolve( __dirname, '../../../client/components/' );
|
||||||
|
const PACKAGES_FOLDER = path.resolve( __dirname, '../../../packages/components/src/' );
|
||||||
const DOCS_FOLDER = path.resolve( __dirname, '../../../docs/components/' );
|
const DOCS_FOLDER = path.resolve( __dirname, '../../../docs/components/' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +79,7 @@ function getMdFileName( filepath, absolute = true ) {
|
||||||
if ( ! fileParts || ! fileParts[ 1 ] ) {
|
if ( ! fileParts || ! fileParts[ 1 ] ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const name = fileParts[ 1 ].split( '/' )[ 0 ];
|
const name = fileParts[ 1 ].replace( 'src/', '' ).split( '/' )[ 0 ];
|
||||||
if ( ! absolute ) {
|
if ( ! absolute ) {
|
||||||
return name + '.md';
|
return name + '.md';
|
||||||
}
|
}
|
||||||
|
@ -148,7 +149,7 @@ function isFile( file ) {
|
||||||
* @param { array } files A list of readme files.
|
* @param { array } files A list of readme files.
|
||||||
*/
|
*/
|
||||||
function writeTableOfContents( files ) {
|
function writeTableOfContents( files ) {
|
||||||
const mdFiles = files.map( f => getMdFileName( f, false ) );
|
const mdFiles = files.map( f => getMdFileName( f, false ) ).sort();
|
||||||
const TOC = uniq( mdFiles ).map( doc => {
|
const TOC = uniq( mdFiles ).map( doc => {
|
||||||
const name = camelCaseDash( doc.replace( '.md', '' ) );
|
const name = camelCaseDash( doc.replace( '.md', '' ) );
|
||||||
return ` * [${ name }](components/${ doc })`;
|
return ` * [${ name }](components/${ doc })`;
|
||||||
|
@ -161,6 +162,7 @@ function writeTableOfContents( files ) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
COMPONENTS_FOLDER,
|
COMPONENTS_FOLDER,
|
||||||
DOCS_FOLDER,
|
DOCS_FOLDER,
|
||||||
|
PACKAGES_FOLDER,
|
||||||
deleteExistingDocs,
|
deleteExistingDocs,
|
||||||
getExportedFileList,
|
getExportedFileList,
|
||||||
getMdFileName,
|
getMdFileName,
|
||||||
|
|
|
@ -174,12 +174,14 @@ install_deps() {
|
||||||
# Install WooCommerce
|
# Install WooCommerce
|
||||||
cd "wp-content/plugins/"
|
cd "wp-content/plugins/"
|
||||||
# As zip file does not include tests, we have to get it from git repo.
|
# As zip file does not include tests, we have to get it from git repo.
|
||||||
git clone https://github.com/woocommerce/woocommerce.git
|
git clone --depth 1 https://github.com/woocommerce/woocommerce.git
|
||||||
cd "$WP_CORE_DIR"
|
cd "$WP_CORE_DIR"
|
||||||
php wp-cli.phar plugin activate woocommerce
|
php wp-cli.phar plugin activate woocommerce
|
||||||
|
|
||||||
# Install wc-admin, the correct branch
|
if [ "$TRAVIS_PULL_REQUEST_BRANCH" != "" ]; then
|
||||||
php wp-cli.phar plugin install https://github.com/$REPO/archive/$BRANCH.zip --activate
|
# Install wc-admin, the correct branch, if running from Travis CI.
|
||||||
|
php wp-cli.phar plugin install https://github.com/$REPO/archive/$BRANCH.zip --activate
|
||||||
|
fi
|
||||||
|
|
||||||
# Back to original dir
|
# Back to original dir
|
||||||
cd "$WORKING_DIR"
|
cd "$WORKING_DIR"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [[ ${RUN_JS} == 1 ]]; then
|
||||||
|
npm run lint
|
||||||
|
npm run build
|
||||||
|
npm test
|
||||||
|
fi
|
|
@ -121,16 +121,14 @@ function buildScssFile( styleFile ) {
|
||||||
mkdirp.sync( path.dirname( outputFile ) );
|
mkdirp.sync( path.dirname( outputFile ) );
|
||||||
const builtSass = sass.renderSync( {
|
const builtSass = sass.renderSync( {
|
||||||
file: styleFile,
|
file: styleFile,
|
||||||
includePaths: [ path.resolve( __dirname, '../../assets/stylesheets' ) ],
|
includePaths: [ path.resolve( __dirname, '../../client/stylesheets/abstracts' ) ],
|
||||||
data: (
|
data: (
|
||||||
[
|
[
|
||||||
'colors',
|
'colors',
|
||||||
'breakpoints',
|
|
||||||
'variables',
|
'variables',
|
||||||
|
'breakpoints',
|
||||||
'mixins',
|
'mixins',
|
||||||
'animations',
|
].map( ( imported ) => `@import "_${ imported }";` ).join( ' ' ) +
|
||||||
'z-index',
|
|
||||||
].map( ( imported ) => `@import "${ imported }";` ).join( ' ' ) +
|
|
||||||
fs.readFileSync( styleFile, 'utf8' )
|
fs.readFileSync( styleFile, 'utf8' )
|
||||||
),
|
),
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = [
|
module.exports = [
|
||||||
require( './node_modules/@wordpress/postcss-themes' )( {
|
require( '@wordpress/postcss-themes' )( {
|
||||||
defaults: {
|
defaults: {
|
||||||
primary: '#0085ba',
|
primary: '#0085ba',
|
||||||
secondary: '#11a0d2',
|
secondary: '#11a0d2',
|
||||||
|
|
|
@ -5,6 +5,7 @@ if [[ ${RUN_PHPCS} == 1 ]]; then
|
||||||
|
|
||||||
if [ "$CHANGED_FILES" != "" ]; then
|
if [ "$CHANGED_FILES" != "" ]; then
|
||||||
echo "Running Code Sniffer."
|
echo "Running Code Sniffer."
|
||||||
|
cd "$WP_CORE_DIR/wp-content/plugins/wc-admin/"
|
||||||
./vendor/bin/phpcs --encoding=utf-8 -n -p $CHANGED_FILES
|
./vendor/bin/phpcs --encoding=utf-8 -n -p $CHANGED_FILES
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
WORKING_DIR="$PWD"
|
WORKING_DIR="$PWD"
|
||||||
cd "/tmp/wordpress/wp-content/plugins/wc-admin/"
|
cd "$WP_CORE_DIR/wp-content/plugins/wc-admin/"
|
||||||
|
phpunit --version
|
||||||
phpunit -c phpunit.xml.dist
|
phpunit -c phpunit.xml.dist
|
||||||
|
TEST_RESULT=$?
|
||||||
cd "$WORKING_DIR"
|
cd "$WORKING_DIR"
|
||||||
|
exit $TEST_RESULT
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
if [ $1 == 'before' ]; then
|
if [ $1 == 'before' ]; then
|
||||||
|
|
||||||
composer global require "phpunit/phpunit=6.*"
|
|
||||||
|
|
||||||
if [[ ${RUN_PHPCS} == 1 ]]; then
|
if [[ ${RUN_PHPCS} == 1 ]]; then
|
||||||
|
cd "$WP_CORE_DIR/wp-content/plugins/wc-admin/"
|
||||||
|
# This can (currently) only run for PHP 7.1+
|
||||||
composer install
|
composer install
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import PropTypes from 'prop-types';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { Chart, ChartPlaceholder } from '@woocommerce/components';
|
|
||||||
import {
|
import {
|
||||||
getAllowedIntervalsForQuery,
|
getAllowedIntervalsForQuery,
|
||||||
getCurrentDates,
|
getCurrentDates,
|
||||||
|
@ -24,12 +23,21 @@ import {
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
import { Chart, ChartPlaceholder } from 'components';
|
||||||
import { getReportChartData } from 'store/reports/utils';
|
import { getReportChartData } from 'store/reports/utils';
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
|
|
||||||
class ReportChart extends Component {
|
class ReportChart extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { path, primaryData, secondaryData, selectedChart, query } = this.props;
|
const {
|
||||||
|
comparisonChart,
|
||||||
|
query,
|
||||||
|
itemsLabel,
|
||||||
|
path,
|
||||||
|
primaryData,
|
||||||
|
secondaryData,
|
||||||
|
selectedChart,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if ( primaryData.isError || secondaryData.isError ) {
|
if ( primaryData.isError || secondaryData.isError ) {
|
||||||
return <ReportError isError />;
|
return <ReportError isError />;
|
||||||
|
@ -84,7 +92,9 @@ class ReportChart extends Component {
|
||||||
title={ selectedChart.label }
|
title={ selectedChart.label }
|
||||||
interval={ currentInterval }
|
interval={ currentInterval }
|
||||||
allowedIntervals={ allowedIntervals }
|
allowedIntervals={ allowedIntervals }
|
||||||
mode="time-comparison"
|
itemsLabel={ itemsLabel }
|
||||||
|
layout={ comparisonChart ? 'comparison' : 'standard' }
|
||||||
|
mode={ comparisonChart ? 'item-comparison' : 'time-comparison' }
|
||||||
pointLabelFormat={ formats.pointLabelFormat }
|
pointLabelFormat={ formats.pointLabelFormat }
|
||||||
tooltipTitle={ selectedChart.label }
|
tooltipTitle={ selectedChart.label }
|
||||||
xFormat={ formats.xFormat }
|
xFormat={ formats.xFormat }
|
||||||
|
@ -97,6 +107,8 @@ class ReportChart extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportChart.propTypes = {
|
ReportChart.propTypes = {
|
||||||
|
comparisonChart: PropTypes.bool,
|
||||||
|
itemsLabel: PropTypes.string,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
primaryData: PropTypes.object.isRequired,
|
primaryData: PropTypes.object.isRequired,
|
||||||
query: PropTypes.object.isRequired,
|
query: PropTypes.object.isRequired,
|
||||||
|
|
|
@ -7,14 +7,14 @@ import { Component } from '@wordpress/element';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { EmptyContent } from '@woocommerce/components';
|
import { EmptyContent } from '@woocommerce/components';
|
||||||
import { getAdminLink } from 'lib/nav-utils';
|
import { getAdminLink } from '@woocommerce/navigation';
|
||||||
|
|
||||||
class ReportError extends Component {
|
class ReportError extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { isError, isEmpty } = this.props;
|
const { className, isError, isEmpty } = this.props;
|
||||||
let title, actionLabel, actionURL, actionCallback;
|
let title, actionLabel, actionURL, actionCallback;
|
||||||
|
|
||||||
if ( isError ) {
|
if ( isError ) {
|
||||||
|
@ -31,6 +31,7 @@ class ReportError extends Component {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<EmptyContent
|
<EmptyContent
|
||||||
|
className={ className }
|
||||||
title={ title }
|
title={ title }
|
||||||
actionLabel={ actionLabel }
|
actionLabel={ actionLabel }
|
||||||
actionURL={ actionURL }
|
actionURL={ actionURL }
|
||||||
|
@ -41,8 +42,13 @@ class ReportError extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportError.propTypes = {
|
ReportError.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
isError: PropTypes.bool,
|
isError: PropTypes.bool,
|
||||||
isEmpty: PropTypes.bool,
|
isEmpty: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ReportError.defaultProps = {
|
||||||
|
className: '',
|
||||||
|
};
|
||||||
|
|
||||||
export default ReportError;
|
export default ReportError;
|
||||||
|
|
|
@ -14,12 +14,12 @@ import PropTypes from 'prop-types';
|
||||||
*/
|
*/
|
||||||
import { formatCurrency } from '@woocommerce/currency';
|
import { formatCurrency } from '@woocommerce/currency';
|
||||||
import { getDateParamsFromQuery } from '@woocommerce/date';
|
import { getDateParamsFromQuery } from '@woocommerce/date';
|
||||||
|
import { getNewPath } from '@woocommerce/navigation';
|
||||||
import { SummaryList, SummaryListPlaceholder, SummaryNumber } from '@woocommerce/components';
|
import { SummaryList, SummaryListPlaceholder, SummaryNumber } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getNewPath } from 'lib/nav-utils';
|
|
||||||
import { getSummaryNumbers } from 'store/reports/utils';
|
import { getSummaryNumbers } from 'store/reports/utils';
|
||||||
import { numberFormat } from 'lib/number';
|
import { numberFormat } from 'lib/number';
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Component, Fragment } from '@wordpress/element';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { filters } from './config';
|
import { filters } from './config';
|
||||||
|
import CouponsReportTable from './table';
|
||||||
import { ReportFilters } from '@woocommerce/components';
|
import { ReportFilters } from '@woocommerce/components';
|
||||||
|
|
||||||
export default class extends Component {
|
export default class extends Component {
|
||||||
|
@ -17,6 +18,7 @@ export default class extends Component {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ReportFilters query={ query } path={ path } filters={ filters } />
|
<ReportFilters query={ query } path={ path } filters={ filters } />
|
||||||
|
<CouponsReportTable query={ query } />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __, _n } from '@wordpress/i18n';
|
||||||
|
import { Component } from '@wordpress/element';
|
||||||
|
import { format as formatDate } from '@wordpress/date';
|
||||||
|
import { compose } from '@wordpress/compose';
|
||||||
|
import { withSelect } from '@wordpress/data';
|
||||||
|
import { get, map, orderBy } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
appendTimestamp,
|
||||||
|
getCurrentDates,
|
||||||
|
getIntervalForQuery,
|
||||||
|
getDateFormatsForInterval,
|
||||||
|
} from '@woocommerce/date';
|
||||||
|
import { Link, TableCard } from '@woocommerce/components';
|
||||||
|
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
||||||
|
import { onQueryChange } from '@woocommerce/navigation';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import ReportError from 'analytics/components/report-error';
|
||||||
|
import { QUERY_DEFAULTS } from 'store/constants';
|
||||||
|
import { getReportChartData, getFilterQuery } from 'store/reports/utils';
|
||||||
|
|
||||||
|
class CouponsReportTable extends Component {
|
||||||
|
getHeadersContent() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: __( 'Coupon Code', 'wc-admin' ),
|
||||||
|
// @TODO it should be the coupon code, not the coupon ID
|
||||||
|
key: 'coupon_id',
|
||||||
|
required: true,
|
||||||
|
isLeftAligned: true,
|
||||||
|
isSortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Orders', 'wc-admin' ),
|
||||||
|
key: 'orders_count',
|
||||||
|
required: true,
|
||||||
|
defaultSort: true,
|
||||||
|
isSortable: true,
|
||||||
|
isNumeric: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'G. Discounted', 'wc-admin' ),
|
||||||
|
key: 'gross_discount',
|
||||||
|
isSortable: true,
|
||||||
|
isNumeric: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Created', 'wc-admin' ),
|
||||||
|
key: 'created',
|
||||||
|
isSortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Expires', 'wc-admin' ),
|
||||||
|
key: 'expires',
|
||||||
|
isSortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Type', 'wc-admin' ),
|
||||||
|
key: 'type',
|
||||||
|
isSortable: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getRowsContent( coupons ) {
|
||||||
|
const { query } = this.props;
|
||||||
|
const currentInterval = getIntervalForQuery( query );
|
||||||
|
const { tableFormat } = getDateFormatsForInterval( currentInterval );
|
||||||
|
|
||||||
|
return map( coupons, coupon => {
|
||||||
|
const { coupon_id, gross_discount, orders_count } = coupon;
|
||||||
|
|
||||||
|
// @TODO must link to the coupon detail report
|
||||||
|
const couponLink = (
|
||||||
|
<Link href="" type="wc-admin">
|
||||||
|
{ coupon_id }
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ordersLink = (
|
||||||
|
<Link
|
||||||
|
href={ '/analytics/orders?filter=advanced&code_includes=' + coupon_id }
|
||||||
|
type="wc-admin"
|
||||||
|
>
|
||||||
|
{ orders_count }
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
// @TODO it should be the coupon code, not the coupon ID
|
||||||
|
{
|
||||||
|
display: couponLink,
|
||||||
|
value: coupon_id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
display: ordersLink,
|
||||||
|
value: orders_count,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
display: formatCurrency( gross_discount ),
|
||||||
|
value: getCurrencyFormatDecimal( gross_discount ),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// @TODO
|
||||||
|
display: formatDate( tableFormat, '' ),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// @TODO
|
||||||
|
display: formatDate( tableFormat, '' ),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// @TODO
|
||||||
|
display: '',
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
getSummary( totals ) {
|
||||||
|
if ( ! totals ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: _n( 'coupon', 'coupons', totals.coupons_count, 'wc-admin' ),
|
||||||
|
value: totals.coupons_count,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ),
|
||||||
|
value: totals.orders_count,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'gross discounted', 'wc-admin' ),
|
||||||
|
value: formatCurrency( totals.gross_discount ),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { coupons, isTableDataError, isTableDataRequesting, primaryData, query } = this.props;
|
||||||
|
|
||||||
|
const isError = isTableDataError || primaryData.isError;
|
||||||
|
|
||||||
|
if ( isError ) {
|
||||||
|
return <ReportError isError />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRequesting = isTableDataRequesting || primaryData.isRequesting;
|
||||||
|
|
||||||
|
const tableQuery = {
|
||||||
|
...query,
|
||||||
|
orderby: query.orderby || 'date',
|
||||||
|
order: query.order || 'asc',
|
||||||
|
};
|
||||||
|
|
||||||
|
const headers = this.getHeadersContent();
|
||||||
|
const orderedCoupons = orderBy( coupons, tableQuery.orderby, tableQuery.order );
|
||||||
|
const rows = this.getRowsContent( orderedCoupons );
|
||||||
|
const rowsPerPage = parseInt( tableQuery.per_page ) || QUERY_DEFAULTS.pageSize;
|
||||||
|
const totalRows = get( primaryData, [ 'data', 'totals', 'coupons_count' ], coupons.length );
|
||||||
|
const summary = primaryData.data.totals ? this.getSummary( primaryData.data.totals ) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableCard
|
||||||
|
title={ __( 'Coupons', 'wc-admin' ) }
|
||||||
|
compareBy={ 'coupons' }
|
||||||
|
ids={ orderedCoupons.map( coupon => coupon.coupon_id ) }
|
||||||
|
rows={ rows }
|
||||||
|
totalRows={ totalRows }
|
||||||
|
rowsPerPage={ rowsPerPage }
|
||||||
|
headers={ headers }
|
||||||
|
isLoading={ isRequesting }
|
||||||
|
onQueryChange={ onQueryChange }
|
||||||
|
query={ tableQuery }
|
||||||
|
summary={ summary }
|
||||||
|
downloadable
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withSelect( ( select, props ) => {
|
||||||
|
const { query } = props;
|
||||||
|
const datesFromQuery = getCurrentDates( query );
|
||||||
|
const primaryData = getReportChartData( 'coupons', 'primary', query, select );
|
||||||
|
const filterQuery = getFilterQuery( 'coupons', query );
|
||||||
|
|
||||||
|
const { getCoupons, isGetCouponsError, isGetCouponsRequesting } = select( 'wc-admin' );
|
||||||
|
const tableQuery = {
|
||||||
|
orderby: query.orderby || 'date',
|
||||||
|
order: query.order || 'asc',
|
||||||
|
page: query.page || 1,
|
||||||
|
per_page: query.per_page || QUERY_DEFAULTS.pageSize,
|
||||||
|
after: appendTimestamp( datesFromQuery.primary.after, 'start' ),
|
||||||
|
before: appendTimestamp( datesFromQuery.primary.before, 'end' ),
|
||||||
|
...filterQuery,
|
||||||
|
};
|
||||||
|
const coupons = getCoupons( tableQuery );
|
||||||
|
const isTableDataError = isGetCouponsError( tableQuery );
|
||||||
|
const isTableDataRequesting = isGetCouponsRequesting( tableQuery );
|
||||||
|
|
||||||
|
return {
|
||||||
|
isTableDataError,
|
||||||
|
isTableDataRequesting,
|
||||||
|
coupons,
|
||||||
|
primaryData,
|
||||||
|
};
|
||||||
|
} )
|
||||||
|
)( CouponsReportTable );
|
|
@ -8,6 +8,11 @@ import { Component, Fragment } from '@wordpress/element';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { find } from 'lodash';
|
import { find } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { useFilters } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
@ -17,7 +22,7 @@ import OrdersReport from './orders';
|
||||||
import ProductsReport from './products';
|
import ProductsReport from './products';
|
||||||
import RevenueReport from './revenue';
|
import RevenueReport from './revenue';
|
||||||
import CouponsReport from './coupons';
|
import CouponsReport from './coupons';
|
||||||
import useFilters from 'components/higher-order/use-filters';
|
import TaxesReport from './taxes';
|
||||||
|
|
||||||
const REPORTS_FILTER = 'woocommerce-reports-list';
|
const REPORTS_FILTER = 'woocommerce-reports-list';
|
||||||
|
|
||||||
|
@ -43,6 +48,11 @@ const getReports = () => {
|
||||||
title: __( 'Coupons', 'wc-admin' ),
|
title: __( 'Coupons', 'wc-admin' ),
|
||||||
component: CouponsReport,
|
component: CouponsReport,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
report: 'taxes',
|
||||||
|
title: __( 'Taxes', 'wc-admin' ),
|
||||||
|
component: TaxesReport,
|
||||||
|
},
|
||||||
] );
|
] );
|
||||||
|
|
||||||
return reports;
|
return reports;
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/** @format */
|
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
|
||||||
import { find } from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import ReportChart from 'analytics/components/report-chart';
|
|
||||||
import ReportSummary from 'analytics/components/report-summary';
|
|
||||||
|
|
||||||
class OrdersReportChart extends Component {
|
|
||||||
getCharts() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: 'orders_count',
|
|
||||||
label: __( 'Orders Count', 'wc-admin' ),
|
|
||||||
type: 'number',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'net_revenue',
|
|
||||||
label: __( 'Net Revenue', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'avg_order_value',
|
|
||||||
label: __( 'Average Order Value', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'avg_items_per_order',
|
|
||||||
label: __( 'Average Items Per Order', 'wc-admin' ),
|
|
||||||
type: 'average',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedChart() {
|
|
||||||
const { query } = this.props;
|
|
||||||
const charts = this.getCharts();
|
|
||||||
const chart = find( charts, { key: query.chart } );
|
|
||||||
if ( chart ) {
|
|
||||||
return chart;
|
|
||||||
}
|
|
||||||
|
|
||||||
return charts[ 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { path, query } = this.props;
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<ReportSummary
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="orders"
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
<ReportChart
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="orders"
|
|
||||||
path={ path }
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OrdersReportChart.propTypes = {
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
query: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default OrdersReportChart;
|
|
|
@ -12,6 +12,29 @@ import { NAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
const { orderStatuses } = wcSettings;
|
const { orderStatuses } = wcSettings;
|
||||||
|
|
||||||
|
export const charts = [
|
||||||
|
{
|
||||||
|
key: 'orders_count',
|
||||||
|
label: __( 'Orders Count', 'wc-admin' ),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'net_revenue',
|
||||||
|
label: __( 'Net Revenue', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'avg_order_value',
|
||||||
|
label: __( 'Average Order Value', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'avg_items_per_order',
|
||||||
|
label: __( 'Average Items Per Order', 'wc-admin' ),
|
||||||
|
type: 'average',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const filters = [
|
export const filters = [
|
||||||
{
|
{
|
||||||
label: __( 'Show', 'wc-admin' ),
|
label: __( 'Show', 'wc-admin' ),
|
||||||
|
|
|
@ -13,9 +13,11 @@ import { ReportFilters } from '@woocommerce/components';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { advancedFilters, filters } from './config';
|
import { advancedFilters, charts, filters } from './config';
|
||||||
import OrdersReportChart from './chart';
|
import getSelectedChart from 'lib/get-selected-chart';
|
||||||
import OrdersReportTable from './table';
|
import OrdersReportTable from './table';
|
||||||
|
import ReportChart from 'analytics/components/report-chart';
|
||||||
|
import ReportSummary from 'analytics/components/report-summary';
|
||||||
|
|
||||||
export default class OrdersReport extends Component {
|
export default class OrdersReport extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
@ -29,7 +31,19 @@ export default class OrdersReport extends Component {
|
||||||
filters={ filters }
|
filters={ filters }
|
||||||
advancedFilters={ advancedFilters }
|
advancedFilters={ advancedFilters }
|
||||||
/>
|
/>
|
||||||
<OrdersReportChart query={ query } path={ path } />
|
<ReportSummary
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="orders"
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
|
<ReportChart
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="orders"
|
||||||
|
path={ path }
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
<OrdersReportTable query={ query } />
|
<OrdersReportTable query={ query } />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,29 +12,25 @@ import { get, map, orderBy } from 'lodash';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { Link, OrderStatus, TableCard, ViewMoreList } from '@woocommerce/components';
|
|
||||||
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
|
||||||
import {
|
import {
|
||||||
appendTimestamp,
|
appendTimestamp,
|
||||||
getCurrentDates,
|
getCurrentDates,
|
||||||
getIntervalForQuery,
|
getIntervalForQuery,
|
||||||
getDateFormatsForInterval,
|
getDateFormatsForInterval,
|
||||||
} from '@woocommerce/date';
|
} from '@woocommerce/date';
|
||||||
|
import { Link, OrderStatus, TableCard, ViewMoreList } from '@woocommerce/components';
|
||||||
|
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
||||||
|
import { getAdminLink, onQueryChange } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getAdminLink, onQueryChange } from 'lib/nav-utils';
|
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
import { QUERY_DEFAULTS } from 'store/constants';
|
import { QUERY_DEFAULTS } from 'store/constants';
|
||||||
import { getReportChartData, getFilterQuery } from 'store/reports/utils';
|
import { getReportChartData, getFilterQuery } from 'store/reports/utils';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
class OrdersReportTable extends Component {
|
class OrdersReportTable extends Component {
|
||||||
constructor( props ) {
|
|
||||||
super( props );
|
|
||||||
}
|
|
||||||
|
|
||||||
getHeadersContent() {
|
getHeadersContent() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/** @format */
|
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
|
||||||
import { find } from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import ReportChart from 'analytics/components/report-chart';
|
|
||||||
import ReportSummary from 'analytics/components/report-summary';
|
|
||||||
|
|
||||||
class ProductsReportChart extends Component {
|
|
||||||
getCharts() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: 'items_sold',
|
|
||||||
label: __( 'Items Sold', 'wc-admin' ),
|
|
||||||
type: 'number',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'gross_revenue',
|
|
||||||
label: __( 'Gross Revenue', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'orders_count',
|
|
||||||
label: __( 'Orders Count', 'wc-admin' ),
|
|
||||||
type: 'number',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedChart() {
|
|
||||||
const { query } = this.props;
|
|
||||||
const charts = this.getCharts();
|
|
||||||
const chart = find( charts, { key: query.chart } );
|
|
||||||
if ( chart ) {
|
|
||||||
return chart;
|
|
||||||
}
|
|
||||||
|
|
||||||
return charts[ 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { path, query } = this.props;
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<ReportSummary
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="products"
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
<ReportChart
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="products"
|
|
||||||
path={ path }
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductsReportChart.propTypes = {
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
query: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProductsReportChart;
|
|
|
@ -10,6 +10,24 @@ import { __ } from '@wordpress/i18n';
|
||||||
import { getRequestByIdString } from 'lib/async-requests';
|
import { getRequestByIdString } from 'lib/async-requests';
|
||||||
import { NAMESPACE } from 'store/constants';
|
import { NAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
|
export const charts = [
|
||||||
|
{
|
||||||
|
key: 'items_sold',
|
||||||
|
label: __( 'Items Sold', 'wc-admin' ),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'gross_revenue',
|
||||||
|
label: __( 'Gross Revenue', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'orders_count',
|
||||||
|
label: __( 'Orders Count', 'wc-admin' ),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const filterConfig = {
|
const filterConfig = {
|
||||||
label: __( 'Show', 'wc-admin' ),
|
label: __( 'Show', 'wc-admin' ),
|
||||||
staticParams: [ 'chart' ],
|
staticParams: [ 'chart' ],
|
||||||
|
@ -42,7 +60,7 @@ const filterConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __( 'Product Comparison', 'wc-admin' ),
|
label: __( 'Product Comparison', 'wc-admin' ),
|
||||||
value: 'compare-product',
|
value: 'compare-products',
|
||||||
settings: {
|
settings: {
|
||||||
type: 'products',
|
type: 'products',
|
||||||
param: 'products',
|
param: 'products',
|
||||||
|
@ -60,7 +78,7 @@ const filterConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __( 'Product Category Comparison', 'wc-admin' ),
|
label: __( 'Product Category Comparison', 'wc-admin' ),
|
||||||
value: 'compare-product_cat',
|
value: 'compare-product_cats',
|
||||||
settings: {
|
settings: {
|
||||||
type: 'product_cats',
|
type: 'product_cats',
|
||||||
param: 'categories',
|
param: 'categories',
|
||||||
|
@ -99,13 +117,21 @@ const variationsConfig = {
|
||||||
label: __( 'Comparison', 'wc-admin' ),
|
label: __( 'Comparison', 'wc-admin' ),
|
||||||
value: 'compare',
|
value: 'compare',
|
||||||
settings: {
|
settings: {
|
||||||
// @TODO create a variations autocompleter
|
type: 'variations',
|
||||||
type: 'products',
|
|
||||||
param: 'variations',
|
param: 'variations',
|
||||||
getLabels: getRequestByIdString( NAMESPACE + 'products', product => ( {
|
getLabels: getRequestByIdString(
|
||||||
id: product.id,
|
query => NAMESPACE + `products/${ query.products }/variations`,
|
||||||
label: product.name,
|
variation => {
|
||||||
} ) ),
|
return {
|
||||||
|
id: variation.id,
|
||||||
|
label: variation.attributes.reduce(
|
||||||
|
( desc, attribute, index, arr ) =>
|
||||||
|
desc + `${ attribute.option }${ arr.length === index + 1 ? '' : ', ' }`,
|
||||||
|
''
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
),
|
||||||
labels: {
|
labels: {
|
||||||
helpText: __( 'Select at least two variations to compare', 'wc-admin' ),
|
helpText: __( 'Select at least two variations to compare', 'wc-admin' ),
|
||||||
placeholder: __( 'Search for variations to compare', 'wc-admin' ),
|
placeholder: __( 'Search for variations to compare', 'wc-admin' ),
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
import { Component, Fragment } from '@wordpress/element';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
@ -13,18 +14,39 @@ import { ReportFilters } from '@woocommerce/components';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { filters } from './config';
|
import { charts, filters } from './config';
|
||||||
import ProductsReportChart from './chart';
|
import getSelectedChart from 'lib/get-selected-chart';
|
||||||
import ProductsReportTable from './table';
|
import ProductsReportTable from './table';
|
||||||
|
import ReportChart from 'analytics/components/report-chart';
|
||||||
|
import ReportSummary from 'analytics/components/report-summary';
|
||||||
|
|
||||||
export default class ProductsReport extends Component {
|
export default class ProductsReport extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { path, query } = this.props;
|
const { path, query } = this.props;
|
||||||
|
|
||||||
|
const itemsLabel =
|
||||||
|
'single_product' === query.filter && !! query.products
|
||||||
|
? __( '%s variations', 'wc-admin' )
|
||||||
|
: __( '%s products', 'wc-admin' );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ReportFilters query={ query } path={ path } filters={ filters } />
|
<ReportFilters query={ query } path={ path } filters={ filters } />
|
||||||
<ProductsReportChart query={ query } path={ path } />
|
<ReportSummary
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="products"
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
|
<ReportChart
|
||||||
|
comparisonChart
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="products"
|
||||||
|
itemsLabel={ itemsLabel }
|
||||||
|
path={ path }
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
<ProductsReportTable query={ query } />
|
<ProductsReportTable query={ query } />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,14 +11,14 @@ import { get, map, orderBy } from 'lodash';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
|
import { appendTimestamp, getCurrentDates } from '@woocommerce/date';
|
||||||
import { Link, TableCard } from '@woocommerce/components';
|
import { Link, TableCard } from '@woocommerce/components';
|
||||||
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
||||||
import { appendTimestamp, getCurrentDates } from '@woocommerce/date';
|
import { getNewPath, getTimeRelatedQuery, onQueryChange } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getNewPath, getTimeRelatedQuery, onQueryChange } from 'lib/nav-utils';
|
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
import { getFilterQuery, getReportChartData } from 'store/reports/utils';
|
import { getFilterQuery, getReportChartData } from 'store/reports/utils';
|
||||||
import { QUERY_DEFAULTS } from 'store/constants';
|
import { QUERY_DEFAULTS } from 'store/constants';
|
||||||
|
@ -183,7 +183,7 @@ class ProductsReportTable extends Component {
|
||||||
labels={ labels }
|
labels={ labels }
|
||||||
ids={ orderedProducts.map( p => p.product_id ) }
|
ids={ orderedProducts.map( p => p.product_id ) }
|
||||||
isLoading={ isRequesting }
|
isLoading={ isRequesting }
|
||||||
compareBy={ 'product' }
|
compareBy={ 'products' }
|
||||||
onQueryChange={ onQueryChange }
|
onQueryChange={ onQueryChange }
|
||||||
query={ tableQuery }
|
query={ tableQuery }
|
||||||
summary={ null } // @TODO
|
summary={ null } // @TODO
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
/** @format */
|
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
|
||||||
import { find } from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import ReportChart from 'analytics/components/report-chart';
|
|
||||||
import ReportSummary from 'analytics/components/report-summary';
|
|
||||||
|
|
||||||
class RevenueReportChart extends Component {
|
|
||||||
getCharts() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: 'gross_revenue',
|
|
||||||
label: __( 'Gross Revenue', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'refunds',
|
|
||||||
label: __( 'Refunds', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'coupons',
|
|
||||||
label: __( 'Coupons', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'taxes',
|
|
||||||
label: __( 'Taxes', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'shipping',
|
|
||||||
label: __( 'Shipping', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'net_revenue',
|
|
||||||
label: __( 'Net Revenue', 'wc-admin' ),
|
|
||||||
type: 'currency',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedChart() {
|
|
||||||
const { query } = this.props;
|
|
||||||
const charts = this.getCharts();
|
|
||||||
const chart = find( charts, { key: query.chart } );
|
|
||||||
if ( chart ) {
|
|
||||||
return chart;
|
|
||||||
}
|
|
||||||
|
|
||||||
return charts[ 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { path, query } = this.props;
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<ReportSummary
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="revenue"
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
<ReportChart
|
|
||||||
charts={ this.getCharts() }
|
|
||||||
endpoint="revenue"
|
|
||||||
path={ path }
|
|
||||||
query={ query }
|
|
||||||
selectedChart={ this.getSelectedChart() }
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RevenueReportChart.propTypes = {
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
query: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RevenueReportChart;
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
export const charts = [
|
||||||
|
{
|
||||||
|
key: 'gross_revenue',
|
||||||
|
label: __( 'Gross Revenue', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'refunds',
|
||||||
|
label: __( 'Refunds', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'coupons',
|
||||||
|
label: __( 'Coupons', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'taxes',
|
||||||
|
label: __( 'Taxes', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'shipping',
|
||||||
|
label: __( 'Shipping', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'net_revenue',
|
||||||
|
label: __( 'Net Revenue', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
];
|
|
@ -13,7 +13,10 @@ import { ReportFilters } from '@woocommerce/components';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import RevenueReportChart from './chart';
|
import { charts } from './config';
|
||||||
|
import getSelectedChart from 'lib/get-selected-chart';
|
||||||
|
import ReportChart from 'analytics/components/report-chart';
|
||||||
|
import ReportSummary from 'analytics/components/report-summary';
|
||||||
import RevenueReportTable from './table';
|
import RevenueReportTable from './table';
|
||||||
|
|
||||||
export default class RevenueReport extends Component {
|
export default class RevenueReport extends Component {
|
||||||
|
@ -23,7 +26,19 @@ export default class RevenueReport extends Component {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ReportFilters query={ query } path={ path } />
|
<ReportFilters query={ query } path={ path } />
|
||||||
<RevenueReportChart query={ query } path={ path } />
|
<ReportSummary
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="revenue"
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
|
<ReportChart
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="revenue"
|
||||||
|
path={ path }
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
<RevenueReportTable query={ query } />
|
<RevenueReportTable query={ query } />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,19 +12,19 @@ import { get, map } from 'lodash';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { Link, TableCard } from '@woocommerce/components';
|
|
||||||
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
|
||||||
import {
|
import {
|
||||||
appendTimestamp,
|
appendTimestamp,
|
||||||
getCurrentDates,
|
getCurrentDates,
|
||||||
getDateFormatsForInterval,
|
getDateFormatsForInterval,
|
||||||
getIntervalForQuery,
|
getIntervalForQuery,
|
||||||
} from '@woocommerce/date';
|
} from '@woocommerce/date';
|
||||||
|
import { Link, TableCard } from '@woocommerce/components';
|
||||||
|
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
||||||
|
import { onQueryChange } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { onQueryChange } from 'lib/nav-utils';
|
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
import { QUERY_DEFAULTS } from 'store/constants';
|
import { QUERY_DEFAULTS } from 'store/constants';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const charts = [
|
||||||
|
{
|
||||||
|
key: 'order_tax',
|
||||||
|
label: __( 'Order Tax', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'total_tax',
|
||||||
|
label: __( 'Total Tax', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'shipping_tax',
|
||||||
|
label: __( 'Shipping Tax', 'wc-admin' ),
|
||||||
|
type: 'currency',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'orders_count',
|
||||||
|
label: __( 'Orders Count', 'wc-admin' ),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const filters = [
|
||||||
|
{
|
||||||
|
label: __( 'Show', 'wc-admin' ),
|
||||||
|
staticParams: [ 'chart' ],
|
||||||
|
param: 'filter',
|
||||||
|
showFilters: () => true,
|
||||||
|
filters: [ { label: __( 'All Taxes', 'wc-admin' ), value: 'all' } ],
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,45 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Component, Fragment } from '@wordpress/element';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { ReportFilters } from '@woocommerce/components';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { charts, filters } from './config';
|
||||||
|
import getSelectedChart from 'lib/get-selected-chart';
|
||||||
|
import ReportChart from 'analytics/components/report-chart';
|
||||||
|
import ReportSummary from 'analytics/components/report-summary';
|
||||||
|
export default class TaxesReport extends Component {
|
||||||
|
render() {
|
||||||
|
const { query, path } = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<ReportFilters query={ query } path={ path } filters={ filters } />
|
||||||
|
<ReportSummary
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="taxes"
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
|
<ReportChart
|
||||||
|
charts={ charts }
|
||||||
|
endpoint="taxes"
|
||||||
|
path={ path }
|
||||||
|
query={ query }
|
||||||
|
selectedChart={ getSelectedChart( query.chart, charts ) }
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TaxesReport.propTypes = {
|
||||||
|
query: PropTypes.object.isRequired,
|
||||||
|
};
|
|
@ -105,6 +105,7 @@ class D3Chart extends Component {
|
||||||
mode,
|
mode,
|
||||||
orderedKeys,
|
orderedKeys,
|
||||||
pointLabelFormat,
|
pointLabelFormat,
|
||||||
|
tooltipPosition,
|
||||||
tooltipFormat,
|
tooltipFormat,
|
||||||
tooltipTitle,
|
tooltipTitle,
|
||||||
type,
|
type,
|
||||||
|
@ -116,7 +117,6 @@ class D3Chart extends Component {
|
||||||
const { width } = this.state;
|
const { width } = this.state;
|
||||||
const calculatedWidth = width || node.offsetWidth;
|
const calculatedWidth = width || node.offsetWidth;
|
||||||
const calculatedHeight = height || node.offsetHeight;
|
const calculatedHeight = height || node.offsetHeight;
|
||||||
const scale = width / node.offsetWidth;
|
|
||||||
const adjHeight = calculatedHeight - margin.top - margin.bottom;
|
const adjHeight = calculatedHeight - margin.top - margin.bottom;
|
||||||
const adjWidth = calculatedWidth - margin.left - margin.right;
|
const adjWidth = calculatedWidth - margin.left - margin.right;
|
||||||
const uniqueKeys = getUniqueKeys( data );
|
const uniqueKeys = getUniqueKeys( data );
|
||||||
|
@ -140,7 +140,7 @@ class D3Chart extends Component {
|
||||||
orderedKeys: newOrderedKeys,
|
orderedKeys: newOrderedKeys,
|
||||||
pointLabelFormat,
|
pointLabelFormat,
|
||||||
parseDate,
|
parseDate,
|
||||||
scale,
|
tooltipPosition,
|
||||||
tooltipFormat: d3TimeFormat( tooltipFormat ),
|
tooltipFormat: d3TimeFormat( tooltipFormat ),
|
||||||
tooltipTitle,
|
tooltipTitle,
|
||||||
type,
|
type,
|
||||||
|
@ -155,7 +155,7 @@ class D3Chart extends Component {
|
||||||
xScale,
|
xScale,
|
||||||
yMax,
|
yMax,
|
||||||
yScale,
|
yScale,
|
||||||
yTickOffset: getYTickOffset( adjHeight, scale, yMax ),
|
yTickOffset: getYTickOffset( adjHeight, yMax ),
|
||||||
yFormat,
|
yFormat,
|
||||||
valueType,
|
valueType,
|
||||||
};
|
};
|
||||||
|
@ -241,6 +241,10 @@ D3Chart.propTypes = {
|
||||||
* if `tooltipTitle` is missing, passed to d3TimeFormat.
|
* if `tooltipTitle` is missing, passed to d3TimeFormat.
|
||||||
*/
|
*/
|
||||||
tooltipFormat: PropTypes.string,
|
tooltipFormat: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* The position where to render the tooltip can be `over` the chart or `below` the chart.
|
||||||
|
*/
|
||||||
|
tooltipPosition: PropTypes.oneOf( [ 'below', 'over' ] ),
|
||||||
/**
|
/**
|
||||||
* A string to use as a title for the tooltip. Takes preference over `tooltipFormat`.
|
* A string to use as a title for the tooltip. Takes preference over `tooltipFormat`.
|
||||||
*/
|
*/
|
||||||
|
@ -280,6 +284,7 @@ D3Chart.defaultProps = {
|
||||||
layout: 'standard',
|
layout: 'standard',
|
||||||
mode: 'item-comparison',
|
mode: 'item-comparison',
|
||||||
tooltipFormat: '%B %d, %Y',
|
tooltipFormat: '%B %d, %Y',
|
||||||
|
tooltipPosition: 'over',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
width: 600,
|
width: 600,
|
||||||
xFormat: '%Y-%m-%d',
|
xFormat: '%Y-%m-%d',
|
||||||
|
|
|
@ -32,7 +32,6 @@ export default class D3Base extends Component {
|
||||||
drawChart: PropTypes.func.isRequired,
|
drawChart: PropTypes.func.isRequired,
|
||||||
getParams: PropTypes.func.isRequired,
|
getParams: PropTypes.func.isRequired,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
width: PropTypes.number,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -41,7 +40,6 @@ export default class D3Base extends Component {
|
||||||
drawChart: null,
|
drawChart: null,
|
||||||
getParams: null,
|
getParams: null,
|
||||||
type: null,
|
type: null,
|
||||||
width: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
chartRef = createRef();
|
chartRef = createRef();
|
||||||
|
@ -61,10 +59,6 @@ export default class D3Base extends Component {
|
||||||
state = { ...state, getParams: nextProps.getParams };
|
state = { ...state, getParams: nextProps.getParams };
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nextProps.width !== prevState.width ) {
|
|
||||||
state = { ...state, width: nextProps.width };
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( nextProps.type !== prevState.type ) {
|
if ( nextProps.type !== prevState.type ) {
|
||||||
state = { ...state, type: nextProps.type };
|
state = { ...state, type: nextProps.type };
|
||||||
}
|
}
|
||||||
|
@ -86,7 +80,6 @@ export default class D3Base extends Component {
|
||||||
return (
|
return (
|
||||||
( nextState.params !== null && ! isEqual( this.state.params, nextState.params ) ) ||
|
( nextState.params !== null && ! isEqual( this.state.params, nextState.params ) ) ||
|
||||||
! isEqual( this.state.data, nextState.data ) ||
|
! isEqual( this.state.data, nextState.data ) ||
|
||||||
this.state.width !== nextState.width ||
|
|
||||||
this.state.type !== nextState.type
|
this.state.type !== nextState.type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -129,6 +122,8 @@ export default class D3Base extends Component {
|
||||||
const svg = d3Select( this.chartRef.current )
|
const svg = d3Select( this.chartRef.current )
|
||||||
.append( 'svg' )
|
.append( 'svg' )
|
||||||
.attr( 'viewBox', `0 0 ${ width } ${ height }` )
|
.attr( 'viewBox', `0 0 ${ width } ${ height }` )
|
||||||
|
.attr( 'height', height )
|
||||||
|
.attr( 'width', width )
|
||||||
.attr( 'preserveAspectRatio', 'xMidYMid meet' );
|
.attr( 'preserveAspectRatio', 'xMidYMid meet' );
|
||||||
|
|
||||||
if ( className ) {
|
if ( className ) {
|
||||||
|
|
|
@ -5,10 +5,14 @@
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Component } from '@wordpress/element';
|
import { Component } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { Card } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import Card from 'components/card';
|
|
||||||
import Chart from './index';
|
import Chart from './index';
|
||||||
import dummyOrders from './test/fixtures/dummy-hour';
|
import dummyOrders from './test/fixtures/dummy-hour';
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,14 @@
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
import { Component, Fragment } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { Card } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import Card from 'components/card';
|
|
||||||
import Chart from './index';
|
import Chart from './index';
|
||||||
import dummyOrders from './test/fixtures/dummy';
|
import dummyOrders from './test/fixtures/dummy';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
```jsx
|
```jsx
|
||||||
import { D3Chart, Legend } from '@woocommerce/components';
|
import { D3Chart, Legend } from 'components';
|
||||||
|
|
||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|
||||||
|
|
|
@ -2,27 +2,29 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { get, isEqual, partial } from 'lodash';
|
|
||||||
import { Component, createRef } from '@wordpress/element';
|
import { Component, createRef } from '@wordpress/element';
|
||||||
import { IconButton, NavigableMenu, SelectControl } from '@wordpress/components';
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { interpolateViridis as d3InterpolateViridis } from 'd3-scale-chromatic';
|
|
||||||
import { formatDefaultLocale as d3FormatDefaultLocale } from 'd3-format';
|
import { formatDefaultLocale as d3FormatDefaultLocale } from 'd3-format';
|
||||||
|
import { get, isEqual, partial } from 'lodash';
|
||||||
import Gridicon from 'gridicons';
|
import Gridicon from 'gridicons';
|
||||||
|
import { IconButton, NavigableMenu, SelectControl } from '@wordpress/components';
|
||||||
|
import { interpolateViridis as d3InterpolateViridis } from 'd3-scale-chromatic';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { withViewportMatch } from '@wordpress/viewport';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { updateQueryString } from '@woocommerce/navigation';
|
||||||
|
import { H, Section } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import D3Chart from './charts';
|
import D3Chart from './charts';
|
||||||
import Legend from './legend';
|
import Legend from './legend';
|
||||||
import { WIDE_BREAKPOINT } from './utils';
|
|
||||||
import { H, Section } from 'components/section';
|
|
||||||
import { gap, gaplarge } from 'stylesheets/abstracts/_variables.scss';
|
|
||||||
import { updateQueryString } from 'lib/nav-utils';
|
|
||||||
|
|
||||||
d3FormatDefaultLocale( {
|
d3FormatDefaultLocale( {
|
||||||
decimal: '.',
|
decimal: '.',
|
||||||
|
@ -57,16 +59,13 @@ function getOrderedKeys( props ) {
|
||||||
class Chart extends Component {
|
class Chart extends Component {
|
||||||
constructor( props ) {
|
constructor( props ) {
|
||||||
super( props );
|
super( props );
|
||||||
this.chartRef = createRef();
|
this.chartBodyRef = createRef();
|
||||||
const wpBody = document.getElementById( 'wpbody' ).getBoundingClientRect().width;
|
|
||||||
const wpWrap = document.getElementById( 'wpwrap' ).getBoundingClientRect().width;
|
|
||||||
const calcGap = wpWrap > 782 ? gaplarge.match( /\d+/ )[ 0 ] : gap.match( /\d+/ )[ 0 ];
|
|
||||||
this.state = {
|
this.state = {
|
||||||
data: props.data,
|
data: props.data,
|
||||||
orderedKeys: getOrderedKeys( props ),
|
orderedKeys: getOrderedKeys( props ),
|
||||||
type: props.type,
|
type: props.type,
|
||||||
visibleData: [ ...props.data ],
|
visibleData: [ ...props.data ],
|
||||||
width: wpBody - 2 * calcGap,
|
width: 0,
|
||||||
};
|
};
|
||||||
this.handleTypeToggle = this.handleTypeToggle.bind( this );
|
this.handleTypeToggle = this.handleTypeToggle.bind( this );
|
||||||
this.handleLegendToggle = this.handleLegendToggle.bind( this );
|
this.handleLegendToggle = this.handleLegendToggle.bind( this );
|
||||||
|
@ -90,6 +89,7 @@ class Chart extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.updateDimensions();
|
||||||
window.addEventListener( 'resize', this.updateDimensions );
|
window.addEventListener( 'resize', this.updateDimensions );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ class Chart extends Component {
|
||||||
|
|
||||||
updateDimensions() {
|
updateDimensions() {
|
||||||
this.setState( {
|
this.setState( {
|
||||||
width: this.chartRef.current.offsetWidth,
|
width: this.chartBodyRef.current.offsetWidth,
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,13 +185,30 @@ class Chart extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getChartHeight() {
|
||||||
|
const { isViewportLarge, isViewportMobile } = this.props;
|
||||||
|
|
||||||
|
if ( isViewportMobile ) {
|
||||||
|
return 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isViewportLarge ) {
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 220;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { orderedKeys, type, visibleData, width } = this.state;
|
const { orderedKeys, type, visibleData, width } = this.state;
|
||||||
const {
|
const {
|
||||||
dateParser,
|
dateParser,
|
||||||
|
itemsLabel,
|
||||||
layout,
|
layout,
|
||||||
mode,
|
mode,
|
||||||
pointLabelFormat,
|
pointLabelFormat,
|
||||||
|
isViewportLarge,
|
||||||
|
isViewportWide,
|
||||||
title,
|
title,
|
||||||
tooltipFormat,
|
tooltipFormat,
|
||||||
tooltipTitle,
|
tooltipTitle,
|
||||||
|
@ -201,19 +218,17 @@ class Chart extends Component {
|
||||||
valueType,
|
valueType,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
let { yFormat } = this.props;
|
let { yFormat } = this.props;
|
||||||
const legendDirection = layout === 'standard' && width >= WIDE_BREAKPOINT ? 'row' : 'column';
|
const legendDirection = layout === 'standard' && isViewportWide ? 'row' : 'column';
|
||||||
const chartDirection = layout === 'comparison' && width >= WIDE_BREAKPOINT ? 'row' : 'column';
|
const chartDirection = layout === 'comparison' && isViewportWide ? 'row' : 'column';
|
||||||
let chartHeight = width > 1329 ? 300 : 220;
|
const chartHeight = this.getChartHeight();
|
||||||
chartHeight = width <= 1329 && width > 783 ? 220 : chartHeight;
|
|
||||||
chartHeight = width <= 783 ? 180 : chartHeight;
|
|
||||||
const legend = (
|
const legend = (
|
||||||
<Legend
|
<Legend
|
||||||
className={ 'woocommerce-chart__legend' }
|
|
||||||
colorScheme={ d3InterpolateViridis }
|
colorScheme={ d3InterpolateViridis }
|
||||||
data={ orderedKeys }
|
data={ orderedKeys }
|
||||||
handleLegendHover={ this.handleLegendHover }
|
handleLegendHover={ this.handleLegendHover }
|
||||||
handleLegendToggle={ this.handleLegendToggle }
|
handleLegendToggle={ this.handleLegendToggle }
|
||||||
legendDirection={ legendDirection }
|
legendDirection={ legendDirection }
|
||||||
|
itemsLabel={ itemsLabel }
|
||||||
valueType={ valueType }
|
valueType={ valueType }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -236,10 +251,10 @@ class Chart extends Component {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="woocommerce-chart" ref={ this.chartRef }>
|
<div className="woocommerce-chart">
|
||||||
<div className="woocommerce-chart__header">
|
<div className="woocommerce-chart__header">
|
||||||
<H className="woocommerce-chart__title">{ title }</H>
|
<H className="woocommerce-chart__title">{ title }</H>
|
||||||
{ width >= WIDE_BREAKPOINT && legendDirection === 'row' && legend }
|
{ isViewportWide && legendDirection === 'row' && legend }
|
||||||
{ this.renderIntervalSelector() }
|
{ this.renderIntervalSelector() }
|
||||||
<NavigableMenu
|
<NavigableMenu
|
||||||
className="woocommerce-chart__types"
|
className="woocommerce-chart__types"
|
||||||
|
@ -276,29 +291,33 @@ class Chart extends Component {
|
||||||
'woocommerce-chart__body',
|
'woocommerce-chart__body',
|
||||||
`woocommerce-chart__body-${ chartDirection }`
|
`woocommerce-chart__body-${ chartDirection }`
|
||||||
) }
|
) }
|
||||||
|
ref={ this.chartBodyRef }
|
||||||
>
|
>
|
||||||
{ width >= WIDE_BREAKPOINT && legendDirection === 'column' && legend }
|
{ isViewportWide && legendDirection === 'column' && legend }
|
||||||
<D3Chart
|
{ width > 0 && (
|
||||||
colorScheme={ d3InterpolateViridis }
|
<D3Chart
|
||||||
data={ visibleData }
|
colorScheme={ d3InterpolateViridis }
|
||||||
dateParser={ dateParser }
|
data={ visibleData }
|
||||||
height={ chartHeight }
|
dateParser={ dateParser }
|
||||||
margin={ margin }
|
height={ chartHeight }
|
||||||
mode={ mode }
|
margin={ margin }
|
||||||
orderedKeys={ orderedKeys }
|
mode={ mode }
|
||||||
pointLabelFormat={ pointLabelFormat }
|
orderedKeys={ orderedKeys }
|
||||||
tooltipFormat={ tooltipFormat }
|
pointLabelFormat={ pointLabelFormat }
|
||||||
tooltipTitle={ tooltipTitle }
|
tooltipFormat={ tooltipFormat }
|
||||||
type={ type }
|
tooltipPosition={ isViewportLarge ? 'over' : 'below' }
|
||||||
interval={ interval }
|
tooltipTitle={ tooltipTitle }
|
||||||
width={ chartDirection === 'row' ? width - 320 : width }
|
type={ type }
|
||||||
xFormat={ xFormat }
|
interval={ interval }
|
||||||
x2Format={ x2Format }
|
width={ chartDirection === 'row' ? width - 320 : width }
|
||||||
yFormat={ yFormat }
|
xFormat={ xFormat }
|
||||||
valueType={ valueType }
|
x2Format={ x2Format }
|
||||||
/>
|
yFormat={ yFormat }
|
||||||
|
valueType={ valueType }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
</div>
|
</div>
|
||||||
{ width < WIDE_BREAKPOINT && <div className="woocommerce-chart__footer">{ legend }</div> }
|
{ ! isViewportWide && <div className="woocommerce-chart__footer">{ legend }</div> }
|
||||||
</Section>
|
</Section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -396,4 +415,8 @@ Chart.defaultProps = {
|
||||||
interval: 'day',
|
interval: 'day',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Chart;
|
export default withViewportMatch( {
|
||||||
|
isViewportMobile: '< medium',
|
||||||
|
isViewportLarge: '>= large',
|
||||||
|
isViewportWide: '>= wide',
|
||||||
|
} )( Chart );
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Component } from '@wordpress/element';
|
import { Component, createRef } from '@wordpress/element';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { sprintf } from '@wordpress/i18n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
|
@ -14,7 +15,7 @@ import { formatCurrency } from '@woocommerce/currency';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './style.scss';
|
import './legend.scss';
|
||||||
import { getColor } from './utils';
|
import { getColor } from './utils';
|
||||||
|
|
||||||
function getFormatedTotal( total, valueType ) {
|
function getFormatedTotal( total, valueType ) {
|
||||||
|
@ -36,65 +37,108 @@ function getFormatedTotal( total, valueType ) {
|
||||||
* A legend specifically designed for the WooCommerce admin charts.
|
* A legend specifically designed for the WooCommerce admin charts.
|
||||||
*/
|
*/
|
||||||
class Legend extends Component {
|
class Legend extends Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.listRef = createRef();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isScrollable: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.updateListScroll();
|
||||||
|
window.addEventListener( 'resize', this.updateListScroll );
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener( 'resize', this.updateListScroll );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateListScroll = () => {
|
||||||
|
const list = this.listRef.current;
|
||||||
|
const scrolledToEnd = list.scrollHeight - list.scrollTop <= list.offsetHeight;
|
||||||
|
this.setState( {
|
||||||
|
isScrollable: ! scrolledToEnd,
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
colorScheme,
|
colorScheme,
|
||||||
data,
|
data,
|
||||||
handleLegendHover,
|
handleLegendHover,
|
||||||
handleLegendToggle,
|
handleLegendToggle,
|
||||||
|
itemsLabel,
|
||||||
legendDirection,
|
legendDirection,
|
||||||
valueType,
|
valueType,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
const { isScrollable } = this.state;
|
||||||
const colorParams = {
|
const colorParams = {
|
||||||
orderedKeys: data,
|
orderedKeys: data,
|
||||||
colorScheme,
|
colorScheme,
|
||||||
};
|
};
|
||||||
const numberOfRowsVisible = data.filter( row => row.visible ).length;
|
const numberOfRowsVisible = data.filter( row => row.visible ).length;
|
||||||
|
const showTotalLabel = legendDirection === 'column' && data.length > 5 && itemsLabel;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul
|
<div
|
||||||
className={ classNames(
|
className={ classNames(
|
||||||
'woocommerce-legend',
|
'woocommerce-legend',
|
||||||
`woocommerce-legend__direction-${ legendDirection }`,
|
`woocommerce-legend__direction-${ legendDirection }`,
|
||||||
|
{
|
||||||
|
'has-total': showTotalLabel,
|
||||||
|
'is-scrollable': isScrollable,
|
||||||
|
},
|
||||||
this.props.className
|
this.props.className
|
||||||
) }
|
) }
|
||||||
>
|
>
|
||||||
{ data.map( row => (
|
<ul
|
||||||
<li
|
className="woocommerce-legend__list"
|
||||||
className={ classNames( 'woocommerce-legend__item', {
|
ref={ this.listRef }
|
||||||
'woocommerce-legend__item-checked': row.visible,
|
onScroll={ showTotalLabel ? this.updateListScroll : null }
|
||||||
} ) }
|
>
|
||||||
key={ row.key }
|
{ data.map( row => (
|
||||||
id={ row.key }
|
<li
|
||||||
onMouseEnter={ handleLegendHover }
|
className={ classNames( 'woocommerce-legend__item', {
|
||||||
onMouseLeave={ handleLegendHover }
|
'woocommerce-legend__item-checked': row.visible,
|
||||||
onBlur={ handleLegendHover }
|
} ) }
|
||||||
onFocus={ handleLegendHover }
|
key={ row.key }
|
||||||
>
|
|
||||||
<button
|
|
||||||
onClick={ handleLegendToggle }
|
|
||||||
id={ row.key }
|
id={ row.key }
|
||||||
disabled={ row.visible && numberOfRowsVisible <= 1 }
|
onMouseEnter={ handleLegendHover }
|
||||||
|
onMouseLeave={ handleLegendHover }
|
||||||
|
onBlur={ handleLegendHover }
|
||||||
|
onFocus={ handleLegendHover }
|
||||||
>
|
>
|
||||||
<div className="woocommerce-legend__item-container" id={ row.key }>
|
<button
|
||||||
<span
|
onClick={ handleLegendToggle }
|
||||||
className={ classNames( 'woocommerce-legend__item-checkmark', {
|
id={ row.key }
|
||||||
'woocommerce-legend__item-checkmark-checked': row.visible,
|
disabled={ row.visible && numberOfRowsVisible <= 1 }
|
||||||
} ) }
|
>
|
||||||
id={ row.key }
|
<div className="woocommerce-legend__item-container" id={ row.key }>
|
||||||
style={ { color: getColor( row.key, colorParams ) } }
|
<span
|
||||||
/>
|
className={ classNames( 'woocommerce-legend__item-checkmark', {
|
||||||
<span className="woocommerce-legend__item-title" id={ row.key }>
|
'woocommerce-legend__item-checkmark-checked': row.visible,
|
||||||
{ row.key }
|
} ) }
|
||||||
</span>
|
id={ row.key }
|
||||||
<span className="woocommerce-legend__item-total" id={ row.key }>
|
style={ { color: getColor( row.key, colorParams ) } }
|
||||||
{ getFormatedTotal( row.total, valueType ) }
|
/>
|
||||||
</span>
|
<span className="woocommerce-legend__item-title" id={ row.key }>
|
||||||
</div>
|
{ row.key }
|
||||||
</button>
|
</span>
|
||||||
</li>
|
<span className="woocommerce-legend__item-total" id={ row.key }>
|
||||||
) ) }
|
{ getFormatedTotal( row.total, valueType ) }
|
||||||
</ul>
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
) ) }
|
||||||
|
</ul>
|
||||||
|
{ showTotalLabel && (
|
||||||
|
<div className="woocommerce-legend__total">{ sprintf( itemsLabel, data.length ) }</div>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +168,11 @@ Legend.propTypes = {
|
||||||
* Display legend items as a `row` or `column` inside a flex-box.
|
* Display legend items as a `row` or `column` inside a flex-box.
|
||||||
*/
|
*/
|
||||||
legendDirection: PropTypes.oneOf( [ 'row', 'column' ] ),
|
legendDirection: PropTypes.oneOf( [ 'row', 'column' ] ),
|
||||||
|
/**
|
||||||
|
* Label to describe the legend items. It will be displayed in the legend of
|
||||||
|
* comparison charts when there are many.
|
||||||
|
*/
|
||||||
|
itemsLabel: PropTypes.string,
|
||||||
/**
|
/**
|
||||||
* What type of data is to be displayed? Number, Average, String?
|
* What type of data is to be displayed? Number, Average, String?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
.woocommerce-legend {
|
||||||
|
&.has-total {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.woocommerce-legend__direction-column {
|
||||||
|
border-right: 1px solid $core-grey-light-700;
|
||||||
|
min-width: 320px;
|
||||||
|
|
||||||
|
.woocommerce-chart__footer & {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__list {
|
||||||
|
color: $black;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
.woocommerce-legend__direction-column & {
|
||||||
|
flex-direction: column;
|
||||||
|
height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.woocommerce-chart__footer & {
|
||||||
|
border-top: 1px solid $core-grey-light-700;
|
||||||
|
height: 100%;
|
||||||
|
max-height: none;
|
||||||
|
min-height: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-total.woocommerce-legend__direction-column & {
|
||||||
|
height: 250px;
|
||||||
|
|
||||||
|
.woocommerce-chart__footer & {
|
||||||
|
height: auto;
|
||||||
|
max-height: 220px;
|
||||||
|
min-height: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__direction-row & {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__item {
|
||||||
|
& > button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: $white;
|
||||||
|
color: $core-grey-dark-500;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.woocommerce-legend__item-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
padding: 3px 0 3px 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
input {
|
||||||
|
~ .woocommerce-legend__item-checkmark {
|
||||||
|
background-color: $core-grey-light-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__item-checkmark {
|
||||||
|
border: 1px solid $core-grey-light-900;
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 0;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
background-color: $white;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.woocommerce-legend__item-checkmark-checked {
|
||||||
|
background-color: currentColor;
|
||||||
|
border-color: currentColor;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: block;
|
||||||
|
left: 5px;
|
||||||
|
top: 2px;
|
||||||
|
width: 3px;
|
||||||
|
height: 6px;
|
||||||
|
border: solid $white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__item-total {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
.woocommerce-legend__item-container {
|
||||||
|
.woocommerce-legend__item-checkmark {
|
||||||
|
outline: 2px solid $core-grey-light-900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $core-grey-light-100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__direction-column & {
|
||||||
|
margin: 2px 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: $gap-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: $gap-small;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__direction-row & {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
padding: 0 17px;
|
||||||
|
|
||||||
|
.woocommerce-legend__item-container {
|
||||||
|
height: 50px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.woocommerce-legend__item-checkmark {
|
||||||
|
top: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__item-title {
|
||||||
|
margin-right: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-legend__total {
|
||||||
|
align-items: center;
|
||||||
|
background: $white;
|
||||||
|
border-top: 1px solid $core-grey-light-700;
|
||||||
|
bottom: 0;
|
||||||
|
color: $core-grey-dark-500;
|
||||||
|
display: flex;
|
||||||
|
height: 50px;
|
||||||
|
justify-content: center;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.2));
|
||||||
|
bottom: 100%;
|
||||||
|
content: '';
|
||||||
|
height: 20px;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-scrollable &::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
.woocommerce-chart {
|
.woocommerce-chart {
|
||||||
margin-top: -$gap;
|
margin-top: -$gap;
|
||||||
margin-bottom: $gap-large;
|
margin-bottom: $gap-large;
|
||||||
background: white;
|
background: $white;
|
||||||
border: 1px solid $core-grey-light-700;
|
border: 1px solid $core-grey-light-700;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
|
|
||||||
|
@ -61,15 +61,6 @@
|
||||||
|
|
||||||
.woocommerce-chart__footer {
|
.woocommerce-chart__footer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.woocommerce-legend {
|
|
||||||
&.woocommerce-legend__direction-column {
|
|
||||||
height: 100%;
|
|
||||||
min-height: none;
|
|
||||||
border-right: none;
|
|
||||||
margin-bottom: $gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@ -185,6 +176,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.y-axis,
|
||||||
|
.axis-month {
|
||||||
|
.tick text {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.focus-grid {
|
.focus-grid {
|
||||||
line {
|
line {
|
||||||
|
@ -252,146 +249,3 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.woocommerce-legend {
|
|
||||||
color: $black;
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
&.woocommerce-legend__direction-column {
|
|
||||||
flex-direction: column;
|
|
||||||
border-right: 1px solid $core-grey-light-700;
|
|
||||||
height: 300px;
|
|
||||||
min-width: 320px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
height: 32px;
|
|
||||||
padding: 0 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 17px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.woocommerce-legend__direction-row {
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
li {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 0 17px;
|
|
||||||
|
|
||||||
.woocommerce-legend__item-container {
|
|
||||||
height: 50px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.woocommerce-legend__item-checkmark {
|
|
||||||
top: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-legend__item-title {
|
|
||||||
margin-right: 17px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
&.woocommerce-legend__item {
|
|
||||||
button {
|
|
||||||
&:hover {
|
|
||||||
background-color: $core-grey-light-100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: $white;
|
|
||||||
color: $core-grey-dark-500;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.woocommerce-legend__item-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: relative;
|
|
||||||
padding: 3px 0 3px 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
user-select: none;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
input {
|
|
||||||
~ .woocommerce-legend__item-checkmark {
|
|
||||||
background-color: $core-grey-light-200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-legend__item-checkmark {
|
|
||||||
border: 1px solid $core-grey-light-900;
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
left: 0;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
background-color: $white;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.woocommerce-legend__item-checkmark-checked {
|
|
||||||
background-color: currentColor;
|
|
||||||
border-color: currentColor;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: block;
|
|
||||||
left: 5px;
|
|
||||||
top: 2px;
|
|
||||||
width: 3px;
|
|
||||||
height: 6px;
|
|
||||||
border: solid $white;
|
|
||||||
border-width: 0 2px 2px 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-legend__item-total {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
.woocommerce-legend__item-container {
|
|
||||||
.woocommerce-legend__item-checkmark {
|
|
||||||
outline: 2px solid $core-grey-light-900;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
import { shallow } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -26,7 +26,7 @@ const data = [
|
||||||
|
|
||||||
describe( 'Legend', () => {
|
describe( 'Legend', () => {
|
||||||
test( 'should not disable any button if more than one is active', () => {
|
test( 'should not disable any button if more than one is active', () => {
|
||||||
const topSellingProducts = shallow( <Legend colorScheme={ colorScheme } data={ data } /> );
|
const topSellingProducts = mount( <Legend colorScheme={ colorScheme } data={ data } /> );
|
||||||
|
|
||||||
expect( topSellingProducts.find( 'button' ).get( 0 ).props.disabled ).toBeFalsy();
|
expect( topSellingProducts.find( 'button' ).get( 0 ).props.disabled ).toBeFalsy();
|
||||||
expect( topSellingProducts.find( 'button' ).get( 1 ).props.disabled ).toBeFalsy();
|
expect( topSellingProducts.find( 'button' ).get( 1 ).props.disabled ).toBeFalsy();
|
||||||
|
@ -35,7 +35,7 @@ describe( 'Legend', () => {
|
||||||
test( 'should disable the last active button', () => {
|
test( 'should disable the last active button', () => {
|
||||||
data[ 1 ].visible = false;
|
data[ 1 ].visible = false;
|
||||||
|
|
||||||
const topSellingProducts = shallow( <Legend colorScheme={ colorScheme } data={ data } /> );
|
const topSellingProducts = mount( <Legend colorScheme={ colorScheme } data={ data } /> );
|
||||||
|
|
||||||
expect( topSellingProducts.find( 'button' ).get( 0 ).props.disabled ).toBeTruthy();
|
expect( topSellingProducts.find( 'button' ).get( 0 ).props.disabled ).toBeTruthy();
|
||||||
expect( topSellingProducts.find( 'button' ).get( 1 ).props.disabled ).toBeFalsy();
|
expect( topSellingProducts.find( 'button' ).get( 1 ).props.disabled ).toBeFalsy();
|
||||||
|
|
|
@ -172,12 +172,9 @@ describe( 'getYScale', () => {
|
||||||
|
|
||||||
describe( 'getYTickOffset', () => {
|
describe( 'getYTickOffset', () => {
|
||||||
it( 'properly scale the y values for the y-axis ticks given the height and maximum y value', () => {
|
it( 'properly scale the y values for the y-axis ticks given the height and maximum y value', () => {
|
||||||
const testYTickOffset1 = getYTickOffset( 100, 1, testYMax );
|
const testYTickOffset1 = getYTickOffset( 100, testYMax );
|
||||||
expect( testYTickOffset1( 0 ) ).toEqual( 112 );
|
expect( testYTickOffset1( 0 ) ).toEqual( 112 );
|
||||||
expect( testYTickOffset1( testYMax ) ).toEqual( 12 );
|
expect( testYTickOffset1( testYMax ) ).toEqual( 12 );
|
||||||
const testYTickOffset2 = getYTickOffset( 100, 2, testYMax );
|
|
||||||
expect( testYTickOffset2( 0 ) ).toEqual( 124 );
|
|
||||||
expect( testYTickOffset2( testYMax ) ).toEqual( 24 );
|
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { format as formatDate } from '@wordpress/date';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { dayTicksThreshold } from '@woocommerce/date';
|
import { dayTicksThreshold, weekTicksThreshold } from '@woocommerce/date';
|
||||||
import { formatCurrency } from '@woocommerce/currency';
|
import { formatCurrency } from '@woocommerce/currency';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -188,14 +188,13 @@ export const getYScale = ( height, yMax ) =>
|
||||||
/**
|
/**
|
||||||
* Describes getyTickOffset
|
* Describes getyTickOffset
|
||||||
* @param {number} height - calculated height of the charting space
|
* @param {number} height - calculated height of the charting space
|
||||||
* @param {number} scale - ratio of the expected width to calculated width (given the viewbox)
|
|
||||||
* @param {number} yMax - from `getYMax`
|
* @param {number} yMax - from `getYMax`
|
||||||
* @returns {function} the D3 linear scale from 0 to the value from `getYMax`, offset by 12 pixels down
|
* @returns {function} the D3 linear scale from 0 to the value from `getYMax`, offset by 12 pixels down
|
||||||
*/
|
*/
|
||||||
export const getYTickOffset = ( height, scale, yMax ) =>
|
export const getYTickOffset = ( height, yMax ) =>
|
||||||
d3ScaleLinear()
|
d3ScaleLinear()
|
||||||
.domain( [ 0, yMax ] )
|
.domain( [ 0, yMax ] )
|
||||||
.rangeRound( [ height + scale * 12, scale * 12 ] );
|
.rangeRound( [ height + 12, 12 ] );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes getyTickOffset
|
* Describes getyTickOffset
|
||||||
|
@ -303,7 +302,10 @@ const calculateXTicksIncrementFactor = ( uniqueDates, maxTicks ) => {
|
||||||
export const getXTicks = ( uniqueDates, width, layout, interval ) => {
|
export const getXTicks = ( uniqueDates, width, layout, interval ) => {
|
||||||
const maxTicks = calculateMaxXTicks( width, layout );
|
const maxTicks = calculateMaxXTicks( width, layout );
|
||||||
|
|
||||||
if ( uniqueDates.length >= dayTicksThreshold && interval === 'day' ) {
|
if (
|
||||||
|
( uniqueDates.length >= dayTicksThreshold && interval === 'day' ) ||
|
||||||
|
( uniqueDates.length >= weekTicksThreshold && interval === 'week' )
|
||||||
|
) {
|
||||||
uniqueDates = getFirstDatePerMonth( uniqueDates );
|
uniqueDates = getFirstDatePerMonth( uniqueDates );
|
||||||
}
|
}
|
||||||
if ( uniqueDates.length <= maxTicks ) {
|
if ( uniqueDates.length <= maxTicks ) {
|
||||||
|
@ -374,6 +376,14 @@ export const compareStrings = ( s1, s2, splitChar = ' ' ) => {
|
||||||
|
|
||||||
export const drawAxis = ( node, params ) => {
|
export const drawAxis = ( node, params ) => {
|
||||||
const xScale = params.type === 'line' ? params.xLineScale : params.xScale;
|
const xScale = params.type === 'line' ? params.xLineScale : params.xScale;
|
||||||
|
const removeDuplicateDates = ( d, i, ticks, formatter ) => {
|
||||||
|
const monthDate = d instanceof Date ? d : new Date( d );
|
||||||
|
let prevMonth = i !== 0 ? ticks[ i - 1 ] : ticks[ i ];
|
||||||
|
prevMonth = prevMonth instanceof Date ? prevMonth : new Date( prevMonth );
|
||||||
|
return i === 0
|
||||||
|
? formatter( monthDate )
|
||||||
|
: compareStrings( formatter( prevMonth ), formatter( monthDate ) ).join( ' ' );
|
||||||
|
};
|
||||||
|
|
||||||
const yGrids = [];
|
const yGrids = [];
|
||||||
for ( let i = 0; i < 4; i++ ) {
|
for ( let i = 0; i < 4; i++ ) {
|
||||||
|
@ -390,7 +400,7 @@ export const drawAxis = ( node, params ) => {
|
||||||
.call(
|
.call(
|
||||||
d3AxisBottom( xScale )
|
d3AxisBottom( xScale )
|
||||||
.tickValues( ticks )
|
.tickValues( ticks )
|
||||||
.tickFormat( d => params.xFormat( d instanceof Date ? d : new Date( d ) ) )
|
.tickFormat( ( d, i ) => removeDuplicateDates( d, i, ticks, params.xFormat ) )
|
||||||
);
|
);
|
||||||
|
|
||||||
node
|
node
|
||||||
|
@ -401,23 +411,10 @@ export const drawAxis = ( node, params ) => {
|
||||||
.call(
|
.call(
|
||||||
d3AxisBottom( xScale )
|
d3AxisBottom( xScale )
|
||||||
.tickValues( ticks )
|
.tickValues( ticks )
|
||||||
.tickFormat( ( d, i ) => {
|
.tickFormat( ( d, i ) => removeDuplicateDates( d, i, ticks, params.x2Format ) )
|
||||||
const monthDate = d instanceof Date ? d : new Date( d );
|
|
||||||
let prevMonth = i !== 0 ? ticks[ i - 1 ] : ticks[ i ];
|
|
||||||
prevMonth = prevMonth instanceof Date ? prevMonth : new Date( prevMonth );
|
|
||||||
return i === 0
|
|
||||||
? params.x2Format( monthDate )
|
|
||||||
: compareStrings( params.x2Format( prevMonth ), params.x2Format( monthDate ) ).join(
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
} )
|
|
||||||
)
|
)
|
||||||
.call( g => g.select( '.domain' ).remove() );
|
.call( g => g.select( '.domain' ).remove() );
|
||||||
|
|
||||||
node
|
|
||||||
.selectAll( '.axis-month .tick text' )
|
|
||||||
.style( 'font-size', `${ Math.round( params.scale * 10 ) }px` );
|
|
||||||
|
|
||||||
node
|
node
|
||||||
.append( 'g' )
|
.append( 'g' )
|
||||||
.attr( 'class', 'pipes' )
|
.attr( 'class', 'pipes' )
|
||||||
|
@ -453,10 +450,6 @@ export const drawAxis = ( node, params ) => {
|
||||||
.tickFormat( d => d3Format( params.yFormat )( d !== 0 ? d : 0 ) )
|
.tickFormat( d => d3Format( params.yFormat )( d !== 0 ? d : 0 ) )
|
||||||
);
|
);
|
||||||
|
|
||||||
node
|
|
||||||
.selectAll( '.y-axis .tick text' )
|
|
||||||
.style( 'font-size', `${ Math.round( params.scale * 10 ) }px` );
|
|
||||||
|
|
||||||
node.selectAll( '.domain' ).remove();
|
node.selectAll( '.domain' ).remove();
|
||||||
node
|
node
|
||||||
.selectAll( '.axis' )
|
.selectAll( '.axis' )
|
||||||
|
@ -541,19 +534,18 @@ const handleMouseOutLineChart = ( parentNode, params ) => {
|
||||||
params.tooltip.style( 'visibility', 'hidden' );
|
params.tooltip.style( 'visibility', 'hidden' );
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WIDE_BREAKPOINT = 1100;
|
|
||||||
|
|
||||||
const calculateTooltipXPosition = (
|
const calculateTooltipXPosition = (
|
||||||
elementCoords,
|
elementCoords,
|
||||||
chartCoords,
|
chartCoords,
|
||||||
tooltipSize,
|
tooltipSize,
|
||||||
tooltipMargin,
|
tooltipMargin,
|
||||||
elementWidthRatio
|
elementWidthRatio,
|
||||||
|
tooltipPosition
|
||||||
) => {
|
) => {
|
||||||
const xPosition =
|
const xPosition =
|
||||||
elementCoords.left + elementCoords.width * elementWidthRatio + tooltipMargin - chartCoords.left;
|
elementCoords.left + elementCoords.width * elementWidthRatio + tooltipMargin - chartCoords.left;
|
||||||
|
|
||||||
if ( chartCoords.width < WIDE_BREAKPOINT ) {
|
if ( tooltipPosition === 'below' ) {
|
||||||
return Math.max(
|
return Math.max(
|
||||||
tooltipMargin,
|
tooltipMargin,
|
||||||
Math.min(
|
Math.min(
|
||||||
|
@ -577,8 +569,14 @@ const calculateTooltipXPosition = (
|
||||||
return xPosition;
|
return xPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateTooltipYPosition = ( elementCoords, chartCoords, tooltipSize, tooltipMargin ) => {
|
const calculateTooltipYPosition = (
|
||||||
if ( chartCoords.width < WIDE_BREAKPOINT ) {
|
elementCoords,
|
||||||
|
chartCoords,
|
||||||
|
tooltipSize,
|
||||||
|
tooltipMargin,
|
||||||
|
tooltipPosition
|
||||||
|
) => {
|
||||||
|
if ( tooltipPosition === 'below' ) {
|
||||||
return chartCoords.height;
|
return chartCoords.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +588,7 @@ const calculateTooltipYPosition = ( elementCoords, chartCoords, tooltipSize, too
|
||||||
return yPosition;
|
return yPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateTooltipPosition = ( element, chart, elementWidthRatio = 1 ) => {
|
const calculateTooltipPosition = ( element, chart, tooltipPosition, elementWidthRatio = 1 ) => {
|
||||||
const elementCoords = element.getBoundingClientRect();
|
const elementCoords = element.getBoundingClientRect();
|
||||||
const chartCoords = chart.getBoundingClientRect();
|
const chartCoords = chart.getBoundingClientRect();
|
||||||
const tooltipSize = d3Select( '.tooltip' )
|
const tooltipSize = d3Select( '.tooltip' )
|
||||||
|
@ -598,7 +596,7 @@ const calculateTooltipPosition = ( element, chart, elementWidthRatio = 1 ) => {
|
||||||
.getBoundingClientRect();
|
.getBoundingClientRect();
|
||||||
const tooltipMargin = 24;
|
const tooltipMargin = 24;
|
||||||
|
|
||||||
if ( chartCoords.width < WIDE_BREAKPOINT ) {
|
if ( tooltipPosition === 'below' ) {
|
||||||
elementWidthRatio = 0;
|
elementWidthRatio = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,9 +606,16 @@ const calculateTooltipPosition = ( element, chart, elementWidthRatio = 1 ) => {
|
||||||
chartCoords,
|
chartCoords,
|
||||||
tooltipSize,
|
tooltipSize,
|
||||||
tooltipMargin,
|
tooltipMargin,
|
||||||
elementWidthRatio
|
elementWidthRatio,
|
||||||
|
tooltipPosition
|
||||||
|
),
|
||||||
|
y: calculateTooltipYPosition(
|
||||||
|
elementCoords,
|
||||||
|
chartCoords,
|
||||||
|
tooltipSize,
|
||||||
|
tooltipMargin,
|
||||||
|
tooltipPosition
|
||||||
),
|
),
|
||||||
y: calculateTooltipYPosition( elementCoords, chartCoords, tooltipSize, tooltipMargin ),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -667,7 +672,11 @@ export const drawLines = ( node, data, params ) => {
|
||||||
return `${ label } ${ formatCurrency( d.value ) }`;
|
return `${ label } ${ formatCurrency( d.value ) }`;
|
||||||
} )
|
} )
|
||||||
.on( 'focus', ( d, i, nodes ) => {
|
.on( 'focus', ( d, i, nodes ) => {
|
||||||
const position = calculateTooltipPosition( d3Event.target, node.node() );
|
const position = calculateTooltipPosition(
|
||||||
|
d3Event.target,
|
||||||
|
node.node(),
|
||||||
|
params.tooltipPosition
|
||||||
|
);
|
||||||
handleMouseOverLineChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
handleMouseOverLineChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
||||||
} )
|
} )
|
||||||
.on( 'blur', ( d, i, nodes ) => handleMouseOutLineChart( nodes[ i ].parentNode, params ) );
|
.on( 'blur', ( d, i, nodes ) => handleMouseOutLineChart( nodes[ i ].parentNode, params ) );
|
||||||
|
@ -715,7 +724,12 @@ export const drawLines = ( node, data, params ) => {
|
||||||
.attr( 'opacity', 0 )
|
.attr( 'opacity', 0 )
|
||||||
.on( 'mouseover', ( d, i, nodes ) => {
|
.on( 'mouseover', ( d, i, nodes ) => {
|
||||||
const elementWidthRatio = i === 0 || i === params.dateSpaces.length - 1 ? 0 : 0.5;
|
const elementWidthRatio = i === 0 || i === params.dateSpaces.length - 1 ? 0 : 0.5;
|
||||||
const position = calculateTooltipPosition( d3Event.target, node.node(), elementWidthRatio );
|
const position = calculateTooltipPosition(
|
||||||
|
d3Event.target,
|
||||||
|
node.node(),
|
||||||
|
params.tooltipPosition,
|
||||||
|
elementWidthRatio
|
||||||
|
);
|
||||||
handleMouseOverLineChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
handleMouseOverLineChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
||||||
} )
|
} )
|
||||||
.on( 'mouseout', ( d, i, nodes ) => handleMouseOutLineChart( nodes[ i ].parentNode, params ) );
|
.on( 'mouseout', ( d, i, nodes ) => handleMouseOutLineChart( nodes[ i ].parentNode, params ) );
|
||||||
|
@ -780,7 +794,7 @@ export const drawBars = ( node, data, params ) => {
|
||||||
} )
|
} )
|
||||||
.on( 'focus', ( d, i, nodes ) => {
|
.on( 'focus', ( d, i, nodes ) => {
|
||||||
const targetNode = d.value > 0 ? d3Event.target : d3Event.target.parentNode;
|
const targetNode = d.value > 0 ? d3Event.target : d3Event.target.parentNode;
|
||||||
const position = calculateTooltipPosition( targetNode, node.node() );
|
const position = calculateTooltipPosition( targetNode, node.node(), params.tooltipPosition );
|
||||||
handleMouseOverBarChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
handleMouseOverBarChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
||||||
} )
|
} )
|
||||||
.on( 'blur', ( d, i, nodes ) => handleMouseOutBarChart( nodes[ i ].parentNode, params ) );
|
.on( 'blur', ( d, i, nodes ) => handleMouseOutBarChart( nodes[ i ].parentNode, params ) );
|
||||||
|
@ -794,7 +808,11 @@ export const drawBars = ( node, data, params ) => {
|
||||||
.attr( 'height', params.height )
|
.attr( 'height', params.height )
|
||||||
.attr( 'opacity', '0' )
|
.attr( 'opacity', '0' )
|
||||||
.on( 'mouseover', ( d, i, nodes ) => {
|
.on( 'mouseover', ( d, i, nodes ) => {
|
||||||
const position = calculateTooltipPosition( d3Event.target, node.node() );
|
const position = calculateTooltipPosition(
|
||||||
|
d3Event.target,
|
||||||
|
node.node(),
|
||||||
|
params.tooltipPosition
|
||||||
|
);
|
||||||
handleMouseOverBarChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
handleMouseOverBarChart( d.date, nodes[ i ].parentNode, node, data, params, position );
|
||||||
} )
|
} )
|
||||||
.on( 'mouseout', ( d, i, nodes ) => handleMouseOutBarChart( nodes[ i ].parentNode, params ) );
|
.on( 'mouseout', ( d, i, nodes ) => handleMouseOutBarChart( nodes[ i ].parentNode, params ) );
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
/** @format */
|
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { omit } from 'lodash';
|
|
||||||
|
|
||||||
export function flatenFilters( filters ) {
|
|
||||||
const allFilters = [];
|
|
||||||
filters.forEach( f => {
|
|
||||||
if ( ! f.subFilters ) {
|
|
||||||
allFilters.push( f );
|
|
||||||
} else {
|
|
||||||
allFilters.push( omit( f, 'subFilters' ) );
|
|
||||||
const subFilters = flatenFilters( f.subFilters );
|
|
||||||
allFilters.push( ...subFilters );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
return allFilters;
|
|
||||||
}
|
|
|
@ -1,52 +1,6 @@
|
||||||
/** @format */
|
/** @format */
|
||||||
|
|
||||||
/**
|
|
||||||
* External Dependencies
|
|
||||||
*/
|
|
||||||
// Turn on react-dates classes/styles, see https://github.com/airbnb/react-dates#initialize
|
|
||||||
import 'react-dates/initialize';
|
|
||||||
|
|
||||||
export { default as AdvancedFilters } from './filters/advanced';
|
|
||||||
export { default as AnimationSlider } from './animation-slider';
|
|
||||||
export { default as Card } from './card';
|
|
||||||
export { default as Chart } from './chart';
|
export { default as Chart } from './chart';
|
||||||
export { default as ChartLegend } from './chart/legend';
|
export { default as ChartLegend } from './chart/legend';
|
||||||
export { default as ChartPlaceholder } from './chart/placeholder';
|
export { default as ChartPlaceholder } from './chart/placeholder';
|
||||||
export { default as Count } from './count';
|
|
||||||
export { default as CompareFilter } from './filters/compare';
|
|
||||||
export { default as D3Chart } from './chart/charts';
|
export { default as D3Chart } from './chart/charts';
|
||||||
export { default as DatePicker } from './filters/date';
|
|
||||||
export { default as DateRange } from './calendar';
|
|
||||||
export { default as DropdownButton } from './dropdown-button';
|
|
||||||
export { default as EllipsisMenu } from './ellipsis-menu';
|
|
||||||
export { default as EmptyContent } from './empty-content';
|
|
||||||
export { default as Flag } from './flag';
|
|
||||||
export { default as FilterPicker } from './filters/filter';
|
|
||||||
export { default as Gravatar } from './gravatar';
|
|
||||||
export { H, Section } from './section';
|
|
||||||
export { default as ImageAsset } from './image-asset';
|
|
||||||
export { default as Link } from './link';
|
|
||||||
export { default as MenuItem } from './ellipsis-menu/menu-item';
|
|
||||||
export { default as MenuTitle } from './ellipsis-menu/menu-title';
|
|
||||||
export { default as OrderStatus } from './order-status';
|
|
||||||
export { default as Pagination } from './pagination';
|
|
||||||
export { default as ProductImage } from './product-image';
|
|
||||||
export { default as ProductRating } from './rating/product';
|
|
||||||
export { default as Rating } from './rating';
|
|
||||||
export { default as ReportFilters } from './filters';
|
|
||||||
export { default as ReviewRating } from './rating/review';
|
|
||||||
export { default as Search } from './search';
|
|
||||||
export { default as SectionHeader } from './section-header';
|
|
||||||
export { default as SegmentedSelection } from './segmented-selection';
|
|
||||||
export { default as SplitButton } from './split-button';
|
|
||||||
export { default as SummaryList } from './summary';
|
|
||||||
export { default as SummaryListPlaceholder } from './summary/placeholder';
|
|
||||||
export { default as SummaryNumber } from './summary/item';
|
|
||||||
export { default as Table } from './table/table';
|
|
||||||
export { default as TableCard } from './table';
|
|
||||||
export { default as EmptyTable } from './table/empty';
|
|
||||||
export { default as TablePlaceholder } from './table/placeholder';
|
|
||||||
export { default as TableSummary } from './table/summary';
|
|
||||||
export { default as Tag } from './tag';
|
|
||||||
export { default as useFilters } from './higher-order/use-filters';
|
|
||||||
export { default as ViewMoreList } from './view-more-list';
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-column-gap: $gap-large;
|
grid-column-gap: $gap-large;
|
||||||
|
|
||||||
@include breakpoint( '<1100px' ) {
|
@include breakpoint( '<960px' ) {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,13 @@ import { withSelect } from '@wordpress/data';
|
||||||
*/
|
*/
|
||||||
import { Card, EmptyTable, TableCard } from '@woocommerce/components';
|
import { Card, EmptyTable, TableCard } from '@woocommerce/components';
|
||||||
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency';
|
||||||
|
import { getAdminLink } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getAdminLink } from 'lib/nav-utils';
|
|
||||||
import { numberFormat } from 'lib/number';
|
import { numberFormat } from 'lib/number';
|
||||||
|
import ReportError from 'analytics/components/report-error';
|
||||||
import { NAMESPACE } from 'store/constants';
|
import { NAMESPACE } from 'store/constants';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ export class TopSellingProducts extends Component {
|
||||||
const title = __( 'Top Selling Products', 'wc-admin' );
|
const title = __( 'Top Selling Products', 'wc-admin' );
|
||||||
|
|
||||||
if ( isError ) {
|
if ( isError ) {
|
||||||
// @TODO An error notice should be displayed when there is an error
|
return <ReportError className="woocommerce-top-selling-products" isError />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! isRequesting && rows.length === 0 ) {
|
if ( ! isRequesting && rows.length === 0 ) {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
/** @format */
|
/** @format */
|
||||||
.woocommerce-top-selling-products {
|
.woocommerce-top-selling-products {
|
||||||
|
&.woocommerce-empty-content {
|
||||||
|
margin-bottom: $gap-large;
|
||||||
|
}
|
||||||
|
|
||||||
.woocommerce-card__body {
|
.woocommerce-card__body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ import PropTypes from 'prop-types';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import * as components from '@woocommerce/components';
|
import * as components from 'components';
|
||||||
|
import * as pkgComponents from '@woocommerce/components';
|
||||||
|
|
||||||
class Example extends Component {
|
class Example extends Component {
|
||||||
state = {
|
state = {
|
||||||
|
@ -28,7 +29,15 @@ class Example extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCode() {
|
async getCode() {
|
||||||
const readme = require( `components/${ this.props.filePath }/example.md` );
|
let readme;
|
||||||
|
try {
|
||||||
|
readme = require( `components/src/${ this.props.filePath }/example.md` );
|
||||||
|
} catch ( e ) {
|
||||||
|
readme = require( `components/${ this.props.filePath }/example.md` );
|
||||||
|
}
|
||||||
|
if ( ! readme ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Example to render is the first jsx code block that appears in the readme
|
// Example to render is the first jsx code block that appears in the readme
|
||||||
let code = codeBlocks( readme ).find( block => 'jsx' === block.lang ).code;
|
let code = codeBlocks( readme ).find( block => 'jsx' === block.lang ).code;
|
||||||
|
@ -47,6 +56,7 @@ class Example extends Component {
|
||||||
const scope = {
|
const scope = {
|
||||||
...wpComponents,
|
...wpComponents,
|
||||||
...components,
|
...components,
|
||||||
|
...pkgComponents,
|
||||||
Component,
|
Component,
|
||||||
withState,
|
withState,
|
||||||
getSettings,
|
getSettings,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @format */
|
/** @format */
|
||||||
|
|
||||||
.woocommerce_devdocs {
|
.woocommerce_devdocs {
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>1280px' ) {
|
||||||
&.is-list {
|
&.is-list {
|
||||||
column-gap: $gap-large;
|
column-gap: $gap-large;
|
||||||
columns: 2;
|
columns: 2;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
@include breakpoint( '<782px' ) {
|
@include breakpoint( '<782px' ) {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: $white;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
top: -3px;
|
top: -3px;
|
||||||
|
@ -20,12 +20,12 @@
|
||||||
flex: 1 100%;
|
flex: 1 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
max-width: 280px;
|
max-width: 280px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
height: 60px;
|
height: 60px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
height: 60px;
|
height: 60px;
|
||||||
border-bottom: 3px solid $white;
|
border-bottom: 3px solid $white;
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,14 +109,14 @@
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
top: 8px;
|
top: 8px;
|
||||||
right: 18px;
|
right: 18px;
|
||||||
left: initial;
|
left: initial;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 28px;
|
right: 28px;
|
||||||
left: initial;
|
left: initial;
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
background: $core-orange;
|
background: $core-orange;
|
||||||
border: 2px solid white;
|
border: 2px solid $white;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -209,10 +209,10 @@
|
||||||
|
|
||||||
// Extra padding is needed at the bottom of the wrapper because of our positioning, height, and overflow rules. Otherwise, some content can get cut off.
|
// Extra padding is needed at the bottom of the wrapper because of our positioning, height, and overflow rules. Otherwise, some content can get cut off.
|
||||||
padding-bottom: $gap-small * 6;
|
padding-bottom: $gap-small * 6;
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
padding-bottom: $gap-small;
|
padding-bottom: $gap-small;
|
||||||
}
|
}
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
top: 112px;
|
top: 112px;
|
||||||
padding-bottom: $gap * 2;
|
padding-bottom: $gap * 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,23 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { Component } from '@wordpress/element';
|
import { Component, findDOMNode } from '@wordpress/element';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
import { Fill } from 'react-slot-fill';
|
import { Fill } from 'react-slot-fill';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ReactDom from 'react-dom';
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { getNewPath, getTimeRelatedQuery } from '@woocommerce/navigation';
|
||||||
|
import { Link } from '@woocommerce/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
import ActivityPanel from './activity-panel';
|
import ActivityPanel from './activity-panel';
|
||||||
import { Link } from '@woocommerce/components';
|
|
||||||
|
|
||||||
class Header extends Component {
|
class Header extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -29,7 +33,7 @@ class Header extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.threshold = ReactDom.findDOMNode( this ).offsetTop;
|
this.threshold = findDOMNode( this ).offsetTop;
|
||||||
window.addEventListener( 'scroll', this.onWindowScroll );
|
window.addEventListener( 'scroll', this.onWindowScroll );
|
||||||
this.updateIsScrolled();
|
this.updateIsScrolled();
|
||||||
}
|
}
|
||||||
|
@ -84,7 +88,10 @@ class Header extends Component {
|
||||||
</span>
|
</span>
|
||||||
{ _sections.map( ( section, i ) => {
|
{ _sections.map( ( section, i ) => {
|
||||||
const sectionPiece = Array.isArray( section ) ? (
|
const sectionPiece = Array.isArray( section ) ? (
|
||||||
<Link href={ section[ 0 ] } type={ isEmbedded ? 'wp-admin' : 'wc-admin' }>
|
<Link
|
||||||
|
href={ getNewPath( getTimeRelatedQuery(), section[ 0 ], {} ) }
|
||||||
|
type={ isEmbedded ? 'wp-admin' : 'wc-admin' }
|
||||||
|
>
|
||||||
{ section[ 1 ] }
|
{ section[ 1 ] }
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
background: $white;
|
background: $white;
|
||||||
|
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
line-height: 80px;
|
line-height: 80px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ import { Component, createElement } from '@wordpress/element';
|
||||||
import { parse } from 'qs';
|
import { parse } from 'qs';
|
||||||
import { find, last } from 'lodash';
|
import { find, last } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { getTimeRelatedQuery, stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +18,6 @@ import Analytics from 'analytics';
|
||||||
import AnalyticsReport from 'analytics/report';
|
import AnalyticsReport from 'analytics/report';
|
||||||
import Dashboard from 'dashboard';
|
import Dashboard from 'dashboard';
|
||||||
import DevDocs from 'devdocs';
|
import DevDocs from 'devdocs';
|
||||||
import { getTimeRelatedQuery, stringifyQuery } from 'lib/nav-utils';
|
|
||||||
|
|
||||||
const getPages = () => {
|
const getPages = () => {
|
||||||
const pages = [
|
const pages = [
|
||||||
|
|
|
@ -8,13 +8,17 @@ import { Slot } from 'react-slot-fill';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { history } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
import { Controller, getPages } from './controller';
|
import { Controller, getPages } from './controller';
|
||||||
import Header from 'header';
|
import Header from 'header';
|
||||||
import history from 'lib/history';
|
|
||||||
import Notices from './notices';
|
import Notices from './notices';
|
||||||
import { recordPageView } from 'lib/tracks';
|
import { recordPageView } from 'lib/tracks';
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
margin: 80px 0 0 $fallback-gutter-large;
|
margin: 80px 0 0 $fallback-gutter-large;
|
||||||
margin: 80px 0 0 $gutter-large;
|
margin: 80px 0 0 $gutter-large;
|
||||||
|
|
||||||
@include breakpoint( '>1100px' ) {
|
@include breakpoint( '>960px' ) {
|
||||||
margin-top: 100px;
|
margin-top: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,21 @@ import apiFetch from '@wordpress/api-fetch';
|
||||||
import { identity } from 'lodash';
|
import { identity } from 'lodash';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { getIdsFromQuery, stringifyQuery } from 'lib/nav-utils';
|
import { getIdsFromQuery, stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a function that accepts ids as they are found in url parameter and
|
* Get a function that accepts ids as they are found in url parameter and
|
||||||
* returns a promise with an optional method applied to results
|
* returns a promise with an optional method applied to results
|
||||||
*
|
*
|
||||||
* @param {string} path - api path
|
* @param {string|function} path - api path string or a function of the query returning api path string
|
||||||
* @param {Function} [handleData] - function applied to each iteration of data
|
* @param {Function} [handleData] - function applied to each iteration of data
|
||||||
* @returns {Function} - a function of ids returning a promise
|
* @returns {Function} - a function of ids returning a promise
|
||||||
*/
|
*/
|
||||||
export function getRequestByIdString( path, handleData = identity ) {
|
export function getRequestByIdString( path, handleData = identity ) {
|
||||||
return function( queryString = '' ) {
|
return function( queryString = '', query ) {
|
||||||
|
const pathString = 'function' === typeof path ? path( query ) : path;
|
||||||
const idList = getIdsFromQuery( queryString );
|
const idList = getIdsFromQuery( queryString );
|
||||||
if ( idList.length < 1 ) {
|
if ( idList.length < 1 ) {
|
||||||
return Promise.resolve( [] );
|
return Promise.resolve( [] );
|
||||||
|
@ -28,6 +29,6 @@ export function getRequestByIdString( path, handleData = identity ) {
|
||||||
include: idList.join( ',' ),
|
include: idList.join( ',' ),
|
||||||
per_page: idList.length,
|
per_page: idList.length,
|
||||||
} );
|
} );
|
||||||
return apiFetch( { path: path + payload } ).then( data => data.map( handleData ) );
|
return apiFetch( { path: pathString + payload } ).then( data => data.map( handleData ) );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { find } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a chart name returns the configuration for that chart from and array
|
||||||
|
* of charts. If the chart is not found it will return the first chart.
|
||||||
|
*
|
||||||
|
* @param {string} chartName - the name of the chart to get configuration for
|
||||||
|
* @param {array} charts - list of charts for a particular report
|
||||||
|
* @returns {object} - chart configuration object
|
||||||
|
*/
|
||||||
|
export default function getSelectedChart( chartName, charts = [] ) {
|
||||||
|
const chart = find( charts, { key: chartName } );
|
||||||
|
if ( chart ) {
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
return charts[ 0 ];
|
||||||
|
}
|
|
@ -1,24 +0,0 @@
|
||||||
Nav Utils
|
|
||||||
=========
|
|
||||||
|
|
||||||
This is a library of functions used in navigation.
|
|
||||||
|
|
||||||
## `getPath()`
|
|
||||||
|
|
||||||
Get the current path from history.
|
|
||||||
|
|
||||||
## `getQuery()`
|
|
||||||
|
|
||||||
Get the current query string, parsed into an object, from history.
|
|
||||||
|
|
||||||
## `getAdminLink( string: path )`
|
|
||||||
|
|
||||||
JS version of `admin_url`. Returns the full URL for a page in wp-admin.
|
|
||||||
|
|
||||||
## `getNewPath( object: query, string: path, object: currentQuery )`
|
|
||||||
|
|
||||||
Return a URL with set query parameters. Optional `path`, `currentQuery`, both will default to the current value fetched from `history` if not provided.
|
|
||||||
|
|
||||||
## `updateQueryString( object: query )`
|
|
||||||
|
|
||||||
Updates the query parameters of the current page.
|
|
|
@ -1,12 +0,0 @@
|
||||||
/** @format */
|
|
||||||
|
|
||||||
// 782px is the width designated by Gutenberg's `</ Popover>` component.
|
|
||||||
// * https://github.com/WordPress/gutenberg/blob/c8f8806d4465a83c1a0bc62d5c61377b56fa7214/components/popover/utils.js#L6
|
|
||||||
export function isMobileViewport() {
|
|
||||||
return window.innerWidth <= 782;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Most screens at 1100px or lower are tablets
|
|
||||||
export function isTabletViewport() {
|
|
||||||
return window.innerWidth > 782 && window.innerWidth <= 1100;
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const NAMESPACE = '/wc/v3/';
|
export const NAMESPACE = '/wc/v3/';
|
||||||
|
export const SWAGGERNAMESPACE = 'https://virtserver.swaggerhub.com/peterfabian/wc-v3-api/1.0.0/';
|
||||||
export const ERROR = 'ERROR';
|
export const ERROR = 'ERROR';
|
||||||
|
|
||||||
// WordPress & WooCommerce both set a hard limit of 100 for the per_page parameter
|
// WordPress & WooCommerce both set a hard limit of 100 for the per_page parameter
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setCoupons( coupons, query ) {
|
||||||
|
return {
|
||||||
|
type: 'SET_COUPONS',
|
||||||
|
coupons,
|
||||||
|
query: query || {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
setCouponsError( query ) {
|
||||||
|
return {
|
||||||
|
type: 'SET_COUPONS_ERROR',
|
||||||
|
query: query || {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import actions from './actions';
|
||||||
|
import reducer from './reducer';
|
||||||
|
import resolvers from './resolvers';
|
||||||
|
import selectors from './selectors';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
actions,
|
||||||
|
reducer,
|
||||||
|
resolvers,
|
||||||
|
selectors,
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { merge } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { ERROR } from 'store/constants';
|
||||||
|
import { getJsonString } from 'store/utils';
|
||||||
|
|
||||||
|
const DEFAULT_STATE = {};
|
||||||
|
|
||||||
|
export default function couponsReducer( state = DEFAULT_STATE, action ) {
|
||||||
|
const queryKey = getJsonString( action.query );
|
||||||
|
|
||||||
|
switch ( action.type ) {
|
||||||
|
case 'SET_COUPONS':
|
||||||
|
return merge( {}, state, {
|
||||||
|
[ queryKey ]: action.coupons,
|
||||||
|
} );
|
||||||
|
|
||||||
|
case 'SET_COUPONS_ERROR':
|
||||||
|
return merge( {}, state, {
|
||||||
|
[ queryKey ]: ERROR,
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/** @format */
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { dispatch } from '@wordpress/data';
|
||||||
|
// import apiFetch from '@wordpress/api-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
// import { NAMESPACE } from 'store/constants';
|
||||||
|
import { SWAGGERNAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async getCoupons( ...args ) {
|
||||||
|
const query = args.length === 1 ? args[ 0 ] : args[ 1 ];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// @TODO update the API endpoint once it's ready
|
||||||
|
// const coupons = await apiFetch( { path: NAMESPACE + 'reports/coupons' + stringifyQuery( query ) } );
|
||||||
|
const response = await fetch(
|
||||||
|
SWAGGERNAMESPACE + 'reports/coupons' + stringifyQuery( query )
|
||||||
|
);
|
||||||
|
const coupons = await response.json();
|
||||||
|
dispatch( 'wc-admin' ).setCoupons( coupons, query );
|
||||||
|
} catch ( error ) {
|
||||||
|
dispatch( 'wc-admin' ).setCouponsError( query );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
/** @format */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { get } from 'lodash';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { getJsonString } from 'store/utils';
|
||||||
|
import { ERROR } from 'store/constants';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns coupons for a specific query.
|
||||||
|
*
|
||||||
|
* @param {Object} state Current state
|
||||||
|
* @param {Object} query Report query parameters
|
||||||
|
* @return {Array} Report details
|
||||||
|
*/
|
||||||
|
function getCoupons( state, query = {} ) {
|
||||||
|
return get( state, [ 'coupons', getJsonString( query ) ], [] );
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getCoupons,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a getCoupons request is pending.
|
||||||
|
*
|
||||||
|
* @param {Object} state Current state
|
||||||
|
* @return {Boolean} True if the `getCoupons` request is pending, false otherwise
|
||||||
|
*/
|
||||||
|
isGetCouponsRequesting( state, ...args ) {
|
||||||
|
return select( 'core/data' ).isResolving( 'wc-admin', 'getCoupons', args );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a getCoupons request has returned an error.
|
||||||
|
*
|
||||||
|
* @param {Object} state Current state
|
||||||
|
* @param {Object} query Query parameters
|
||||||
|
* @return {Boolean} True if the `getCoupons` request has failed, false otherwise
|
||||||
|
*/
|
||||||
|
isGetCouponsError( state, query ) {
|
||||||
|
return ERROR === getCoupons( state, query );
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import deepFreeze from 'deep-freeze';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { ERROR } from 'store/constants';
|
||||||
|
import couponsReducer from '../reducer';
|
||||||
|
import { getJsonString } from 'store/utils';
|
||||||
|
|
||||||
|
describe( 'couponsReducer()', () => {
|
||||||
|
it( 'returns an empty data object by default', () => {
|
||||||
|
const state = couponsReducer( undefined, {} );
|
||||||
|
expect( state ).toEqual( {} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns with received coupons data', () => {
|
||||||
|
const originalState = deepFreeze( {} );
|
||||||
|
const query = {
|
||||||
|
orderby: 'orders_count',
|
||||||
|
};
|
||||||
|
const coupons = [ { coupon_id: 1214 }, { coupon_id: 1215 }, { coupon_id: 1216 } ];
|
||||||
|
|
||||||
|
const state = couponsReducer( originalState, {
|
||||||
|
type: 'SET_COUPONS',
|
||||||
|
query,
|
||||||
|
coupons,
|
||||||
|
} );
|
||||||
|
|
||||||
|
const queryKey = getJsonString( query );
|
||||||
|
expect( state[ queryKey ] ).toEqual( coupons );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'tracks multiple queries in coupons data', () => {
|
||||||
|
const otherQuery = {
|
||||||
|
orderby: 'coupon_id',
|
||||||
|
};
|
||||||
|
const otherQueryKey = getJsonString( otherQuery );
|
||||||
|
const otherCoupons = [ { coupon_id: 1 }, { coupon_id: 2 }, { coupon_id: 3 } ];
|
||||||
|
const otherQueryState = {
|
||||||
|
[ otherQueryKey ]: otherCoupons,
|
||||||
|
};
|
||||||
|
const originalState = deepFreeze( otherQueryState );
|
||||||
|
const query = {
|
||||||
|
orderby: 'orders_count',
|
||||||
|
};
|
||||||
|
const coupons = [ { coupon_id: 1214 }, { coupon_id: 1215 }, { coupon_id: 1216 } ];
|
||||||
|
|
||||||
|
const state = couponsReducer( originalState, {
|
||||||
|
type: 'SET_COUPONS',
|
||||||
|
query,
|
||||||
|
coupons,
|
||||||
|
} );
|
||||||
|
|
||||||
|
const queryKey = getJsonString( query );
|
||||||
|
expect( state[ queryKey ] ).toEqual( coupons );
|
||||||
|
expect( state[ otherQueryKey ] ).toEqual( otherCoupons );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns with received error data', () => {
|
||||||
|
const originalState = deepFreeze( {} );
|
||||||
|
const query = {
|
||||||
|
orderby: 'orders_count',
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = couponsReducer( originalState, {
|
||||||
|
type: 'SET_COUPONS_ERROR',
|
||||||
|
query,
|
||||||
|
} );
|
||||||
|
|
||||||
|
const queryKey = getJsonString( query );
|
||||||
|
expect( state[ queryKey ] ).toEqual( ERROR );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
|
import { dispatch } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import resolvers from '../resolvers';
|
||||||
|
|
||||||
|
const { getCoupons } = resolvers;
|
||||||
|
|
||||||
|
jest.mock( '@wordpress/data', () => ( {
|
||||||
|
dispatch: jest.fn().mockReturnValue( {
|
||||||
|
setCoupons: jest.fn(),
|
||||||
|
} ),
|
||||||
|
} ) );
|
||||||
|
jest.mock( '@wordpress/api-fetch', () => jest.fn() );
|
||||||
|
|
||||||
|
// @TODO reactivate tests when we use the correct API routes instead of swaggerhub
|
||||||
|
xdescribe( 'getCoupons', () => {
|
||||||
|
const COUPONS_1 = [ { coupon_id: 1214 }, { coupon_id: 1215 }, { coupon_id: 1216 } ];
|
||||||
|
|
||||||
|
const COUPONS_2 = [ { coupon_id: 1 }, { coupon_id: 2 }, { coupon_id: 3 } ];
|
||||||
|
|
||||||
|
beforeAll( () => {
|
||||||
|
apiFetch.mockImplementation( options => {
|
||||||
|
if ( options.path === '/wc/v3/reports/coupons' ) {
|
||||||
|
return Promise.resolve( COUPONS_1 );
|
||||||
|
}
|
||||||
|
if ( options.path === '/wc/v3/reports/coupons?orderby=coupon_id' ) {
|
||||||
|
return Promise.resolve( COUPONS_2 );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns requested report data', async () => {
|
||||||
|
expect.assertions( 1 );
|
||||||
|
await getCoupons();
|
||||||
|
expect( dispatch().setCoupons ).toHaveBeenCalledWith( COUPONS_1, undefined );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns requested report data for a specific query', async () => {
|
||||||
|
expect.assertions( 1 );
|
||||||
|
await getCoupons( { orderby: 'coupon_id' } );
|
||||||
|
expect( dispatch().setCoupons ).toHaveBeenCalledWith( COUPONS_2, { orderby: 'coupon_id' } );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import deepFreeze from 'deep-freeze';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { ERROR } from 'store/constants';
|
||||||
|
import { getJsonString } from 'store/utils';
|
||||||
|
import selectors from '../selectors';
|
||||||
|
|
||||||
|
const { getCoupons, isGetCouponsRequesting, isGetCouponsError } = selectors;
|
||||||
|
jest.mock( '@wordpress/data', () => ( {
|
||||||
|
...require.requireActual( '@wordpress/data' ),
|
||||||
|
select: jest.fn().mockReturnValue( {} ),
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
const query = { orderby: 'date' };
|
||||||
|
const queryKey = getJsonString( query );
|
||||||
|
|
||||||
|
describe( 'getCoupons()', () => {
|
||||||
|
it( 'returns an empty array when no coupons are available', () => {
|
||||||
|
const state = deepFreeze( {} );
|
||||||
|
expect( getCoupons( state, query ) ).toEqual( [] );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns stored coupons for current query', () => {
|
||||||
|
const coupons = [ { coupon_id: 1214 }, { coupon_id: 1215 }, { coupon_id: 1216 } ];
|
||||||
|
const state = deepFreeze( {
|
||||||
|
coupons: {
|
||||||
|
[ queryKey ]: coupons,
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
expect( getCoupons( state, query ) ).toEqual( coupons );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
describe( 'isGetCouponsRequesting()', () => {
|
||||||
|
beforeAll( () => {
|
||||||
|
select( 'core/data' ).isResolving = jest.fn().mockReturnValue( false );
|
||||||
|
} );
|
||||||
|
|
||||||
|
afterAll( () => {
|
||||||
|
select( 'core/data' ).isResolving.mockRestore();
|
||||||
|
} );
|
||||||
|
|
||||||
|
function setIsResolving( isResolving ) {
|
||||||
|
select( 'core/data' ).isResolving.mockImplementation(
|
||||||
|
( reducerKey, selectorName ) =>
|
||||||
|
isResolving && reducerKey === 'wc-admin' && selectorName === 'getCoupons'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it( 'returns false if never requested', () => {
|
||||||
|
const result = isGetCouponsRequesting( query );
|
||||||
|
expect( result ).toBe( false );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns false if request finished', () => {
|
||||||
|
setIsResolving( false );
|
||||||
|
const result = isGetCouponsRequesting( query );
|
||||||
|
expect( result ).toBe( false );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns true if requesting', () => {
|
||||||
|
setIsResolving( true );
|
||||||
|
const result = isGetCouponsRequesting( query );
|
||||||
|
expect( result ).toBe( true );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
describe( 'isGetCouponsError()', () => {
|
||||||
|
it( 'returns false by default', () => {
|
||||||
|
const state = deepFreeze( {} );
|
||||||
|
expect( isGetCouponsError( state, query ) ).toEqual( false );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'returns true if ERROR constant is found', () => {
|
||||||
|
const state = deepFreeze( {
|
||||||
|
coupons: {
|
||||||
|
[ queryKey ]: ERROR,
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
expect( isGetCouponsError( state, query ) ).toEqual( true );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -2,13 +2,13 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { registerStore } from '@wordpress/data';
|
import { combineReducers, registerStore } from '@wordpress/data';
|
||||||
import { combineReducers } from 'redux';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { applyMiddleware, addThunks } from './middleware';
|
import { applyMiddleware, addThunks } from './middleware';
|
||||||
|
import coupons from 'store/coupons';
|
||||||
import orders from 'store/orders';
|
import orders from 'store/orders';
|
||||||
import products from 'store/products';
|
import products from 'store/products';
|
||||||
import reports from 'store/reports';
|
import reports from 'store/reports';
|
||||||
|
@ -16,6 +16,7 @@ import notes from 'store/notes';
|
||||||
|
|
||||||
const store = registerStore( 'wc-admin', {
|
const store = registerStore( 'wc-admin', {
|
||||||
reducer: combineReducers( {
|
reducer: combineReducers( {
|
||||||
|
coupons: coupons.reducer,
|
||||||
orders: orders.reducer,
|
orders: orders.reducer,
|
||||||
products: products.reducer,
|
products: products.reducer,
|
||||||
reports: reports.reducer,
|
reports: reports.reducer,
|
||||||
|
@ -23,6 +24,7 @@ const store = registerStore( 'wc-admin', {
|
||||||
} ),
|
} ),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
...coupons.actions,
|
||||||
...orders.actions,
|
...orders.actions,
|
||||||
...products.actions,
|
...products.actions,
|
||||||
...reports.actions,
|
...reports.actions,
|
||||||
|
@ -30,6 +32,7 @@ const store = registerStore( 'wc-admin', {
|
||||||
},
|
},
|
||||||
|
|
||||||
selectors: {
|
selectors: {
|
||||||
|
...coupons.selectors,
|
||||||
...orders.selectors,
|
...orders.selectors,
|
||||||
...products.selectors,
|
...products.selectors,
|
||||||
...reports.selectors,
|
...reports.selectors,
|
||||||
|
@ -37,6 +40,7 @@ const store = registerStore( 'wc-admin', {
|
||||||
},
|
},
|
||||||
|
|
||||||
resolvers: {
|
resolvers: {
|
||||||
|
...coupons.resolvers,
|
||||||
...orders.resolvers,
|
...orders.resolvers,
|
||||||
...products.resolvers,
|
...products.resolvers,
|
||||||
...reports.resolvers,
|
...reports.resolvers,
|
||||||
|
|
|
@ -1,19 +1,27 @@
|
||||||
/** @format */
|
/** @format */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { dispatch } from '@wordpress/data';
|
import { dispatch } from '@wordpress/data';
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { stringifyQuery } from 'lib/nav-utils';
|
|
||||||
import { NAMESPACE } from 'store/constants';
|
import { NAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getNotes( state, query ) {
|
// TODO: Use controls data plugin or fresh-data instead of async
|
||||||
|
async getNotes( ...args ) {
|
||||||
|
// This is interim code to work with either 2.x or 3.x version of @wordpress/data
|
||||||
|
// TODO: Change to just `getNotes( query )` after Gutenberg plugin uses @wordpress/data 3+
|
||||||
|
const query = args.length === 1 ? args[ 0 ] : args[ 1 ];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const notes = await apiFetch( { path: NAMESPACE + 'admin/notes' + stringifyQuery( query ) } );
|
const notes = await apiFetch( { path: NAMESPACE + 'admin/notes' + stringifyQuery( query ) } );
|
||||||
dispatch( 'wc-admin' ).setNotes( notes, query );
|
dispatch( 'wc-admin' ).setNotes( notes, query );
|
||||||
|
|
|
@ -40,13 +40,13 @@ describe( 'getNotes', () => {
|
||||||
|
|
||||||
it( 'returns requested data', async () => {
|
it( 'returns requested data', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getNotes( {} );
|
await getNotes();
|
||||||
expect( dispatch().setNotes ).toHaveBeenCalledWith( NOTES_1, undefined );
|
expect( dispatch().setNotes ).toHaveBeenCalledWith( NOTES_1, undefined );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'returns requested data for a specific query', async () => {
|
it( 'returns requested data for a specific query', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getNotes( {}, { page: 2 } );
|
await getNotes( { page: 2 } );
|
||||||
expect( dispatch().setNotes ).toHaveBeenCalledWith( NOTES_2, { page: 2 } );
|
expect( dispatch().setNotes ).toHaveBeenCalledWith( NOTES_2, { page: 2 } );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import reducer from './reducer';
|
|
||||||
import actions from './actions';
|
import actions from './actions';
|
||||||
import selectors from './selectors';
|
import reducer from './reducer';
|
||||||
import resolvers from './resolvers';
|
import resolvers from './resolvers';
|
||||||
|
import selectors from './selectors';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
reducer,
|
|
||||||
actions,
|
actions,
|
||||||
selectors,
|
reducer,
|
||||||
resolvers,
|
resolvers,
|
||||||
|
selectors,
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,14 +5,23 @@
|
||||||
import { dispatch } from '@wordpress/data';
|
import { dispatch } from '@wordpress/data';
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { stringifyQuery } from 'lib/nav-utils';
|
|
||||||
import { NAMESPACE } from 'store/constants';
|
import { NAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getOrders( state, query ) {
|
// TODO: Use controls data plugin or fresh-data instead of async
|
||||||
|
async getOrders( ...args ) {
|
||||||
|
// This is interim code to work with either 2.x or 3.x version of @wordpress/data
|
||||||
|
// TODO: Change to just `getNotes( query )` after Gutenberg plugin uses @wordpress/data 3+
|
||||||
|
const query = args.length === 1 ? args[ 0 ] : args[ 1 ];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const orders = await apiFetch( { path: NAMESPACE + 'orders' + stringifyQuery( query ) } );
|
const orders = await apiFetch( { path: NAMESPACE + 'orders' + stringifyQuery( query ) } );
|
||||||
dispatch( 'wc-admin' ).setOrders( orders, query );
|
dispatch( 'wc-admin' ).setOrders( orders, query );
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { ERROR } from 'store/constants';
|
||||||
* Returns orders for a specific query.
|
* Returns orders for a specific query.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @param {Object} query Report query paremters
|
* @param {Object} query Report query parameters
|
||||||
* @return {Array} Report details
|
* @return {Array} Report details
|
||||||
*/
|
*/
|
||||||
function getOrders( state, query = {} ) {
|
function getOrders( state, query = {} ) {
|
||||||
|
@ -27,7 +27,7 @@ export default {
|
||||||
getOrders,
|
getOrders,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a query is pending.
|
* Returns true if a getOrders request is pending.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @return {Boolean} True if the `getOrders` request is pending, false otherwise
|
* @return {Boolean} True if the `getOrders` request is pending, false otherwise
|
||||||
|
@ -37,7 +37,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a get orders request has returned an error.
|
* Returns true if a getOrders request has returned an error.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @param {Object} query Query parameters
|
* @param {Object} query Query parameters
|
||||||
|
|
|
@ -40,13 +40,13 @@ describe( 'getOrders', () => {
|
||||||
|
|
||||||
it( 'returns requested report data', async () => {
|
it( 'returns requested report data', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getOrders( {} );
|
await getOrders();
|
||||||
expect( dispatch().setOrders ).toHaveBeenCalledWith( ORDERS_1, undefined );
|
expect( dispatch().setOrders ).toHaveBeenCalledWith( ORDERS_1, undefined );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'returns requested report data for a specific query', async () => {
|
it( 'returns requested report data for a specific query', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getOrders( {}, { orderby: 'id' } );
|
await getOrders( { orderby: 'id' } );
|
||||||
expect( dispatch().setOrders ).toHaveBeenCalledWith( ORDERS_2, { orderby: 'id' } );
|
expect( dispatch().setOrders ).toHaveBeenCalledWith( ORDERS_2, { orderby: 'id' } );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import deepFreeze from 'deep-freeze';
|
import deepFreeze from 'deep-freeze';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { ERROR } from 'store/constants';
|
import { ERROR } from 'store/constants';
|
||||||
import selectors from '../selectors';
|
import selectors from '../selectors';
|
||||||
import { select } from '@wordpress/data';
|
|
||||||
import { getJsonString } from 'store/utils';
|
import { getJsonString } from 'store/utils';
|
||||||
|
|
||||||
const { getOrders, isGetOrdersRequesting, isGetOrdersError } = selectors;
|
const { getOrders, isGetOrdersRequesting, isGetOrdersError } = selectors;
|
||||||
|
|
|
@ -6,11 +6,21 @@ import apiFetch from '@wordpress/api-fetch';
|
||||||
import { dispatch } from '@wordpress/data';
|
import { dispatch } from '@wordpress/data';
|
||||||
import { stringify } from 'qs';
|
import { stringify } from 'qs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { NAMESPACE } from 'store/constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getProducts( state, query ) {
|
// TODO: Use controls data plugin or fresh-data instead of async
|
||||||
|
async getProducts( ...args ) {
|
||||||
|
// This is interim code to work with either 2.x or 3.x version of @wordpress/data
|
||||||
|
// TODO: Change to just `getNotes( query )` after Gutenberg plugin uses @wordpress/data 3+
|
||||||
|
const query = args.length === 1 ? args[ 0 ] : args[ 1 ];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const params = query ? '?' + stringify( query ) : '';
|
const params = query ? '?' + stringify( query ) : '';
|
||||||
const products = await apiFetch( { path: '/wc/v3/reports/products' + params } );
|
const products = await apiFetch( { path: NAMESPACE + 'reports/products' + params } );
|
||||||
dispatch( 'wc-admin' ).setProducts( products, query );
|
dispatch( 'wc-admin' ).setProducts( products, query );
|
||||||
} catch ( error ) {
|
} catch ( error ) {
|
||||||
dispatch( 'wc-admin' ).setProductsError( query );
|
dispatch( 'wc-admin' ).setProductsError( query );
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { getJsonString } from 'store/utils';
|
||||||
* Returns products report details for a specific report query.
|
* Returns products report details for a specific report query.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @param {Object} query Report query paremters
|
* @param {Object} query Report query parameters
|
||||||
* @return {Object} Report details
|
* @return {Object} Report details
|
||||||
*/
|
*/
|
||||||
function getProducts( state, query = {} ) {
|
function getProducts( state, query = {} ) {
|
||||||
|
@ -27,21 +27,21 @@ export default {
|
||||||
getProducts,
|
getProducts,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a products request is pending.
|
* Returns true if a getProducts request is pending.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @return {Object} True if the `getProducts` request is pending, false otherwise
|
* @return {Boolean} True if the `getProducts` request is pending, false otherwise
|
||||||
*/
|
*/
|
||||||
isGetProductsRequesting( state, ...args ) {
|
isGetProductsRequesting( state, ...args ) {
|
||||||
return select( 'core/data' ).isResolving( 'wc-admin', 'getProducts', args );
|
return select( 'core/data' ).isResolving( 'wc-admin', 'getProducts', args );
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a products request has returned an error.
|
* Returns true if a getProducts request has returned an error.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @param {Object} query Report query paremters
|
* @param {Object} query Report query parameters
|
||||||
* @return {Object} True if the `getProducts` request has failed, false otherwise
|
* @return {Boolean} True if the `getProducts` request has failed, false otherwise
|
||||||
*/
|
*/
|
||||||
isGetProductsError( state, query ) {
|
isGetProductsError( state, query ) {
|
||||||
return ERROR === getProducts( state, query );
|
return ERROR === getProducts( state, query );
|
||||||
|
|
|
@ -57,13 +57,13 @@ describe( 'getProducts', () => {
|
||||||
|
|
||||||
it( 'returns requested products', async () => {
|
it( 'returns requested products', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getProducts( {} );
|
await getProducts();
|
||||||
expect( dispatch().setProducts ).toHaveBeenCalledWith( PRODUCTS_1, undefined );
|
expect( dispatch().setProducts ).toHaveBeenCalledWith( PRODUCTS_1, undefined );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'returns requested products for a specific query', async () => {
|
it( 'returns requested products for a specific query', async () => {
|
||||||
expect.assertions( 1 );
|
expect.assertions( 1 );
|
||||||
await getProducts( {}, { orderby: 'date' } );
|
await getProducts( { orderby: 'date' } );
|
||||||
expect( dispatch().setProducts ).toHaveBeenCalledWith( PRODUCTS_2, { orderby: 'date' } );
|
expect( dispatch().setProducts ).toHaveBeenCalledWith( PRODUCTS_2, { orderby: 'date' } );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import deepFreeze from 'deep-freeze';
|
import deepFreeze from 'deep-freeze';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { ERROR } from 'store/constants';
|
import { ERROR } from 'store/constants';
|
||||||
import selectors from '../selectors';
|
import selectors from '../selectors';
|
||||||
import { select } from '@wordpress/data';
|
|
||||||
import { getJsonString } from 'store/utils';
|
import { getJsonString } from 'store/utils';
|
||||||
|
|
||||||
const { getProducts, isGetProductsRequesting, isGetProductsError } = selectors;
|
const { getProducts, isGetProductsRequesting, isGetProductsError } = selectors;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import actions from './actions';
|
import actions from './actions';
|
||||||
import selectors from './selectors';
|
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
import resolvers from './resolvers';
|
import resolvers from './resolvers';
|
||||||
|
import selectors from './selectors';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
actions,
|
actions,
|
||||||
selectors,
|
|
||||||
reducer,
|
reducer,
|
||||||
resolvers,
|
resolvers,
|
||||||
|
selectors,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,17 +6,42 @@
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
import { dispatch } from '@wordpress/data';
|
import { dispatch } from '@wordpress/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WooCommerce dependencies
|
||||||
|
*/
|
||||||
|
import { stringifyQuery } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { stringifyQuery } from 'lib/nav-utils';
|
import { NAMESPACE, SWAGGERNAMESPACE } from 'store/constants';
|
||||||
import { NAMESPACE } from 'store/constants';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async getReportStats( state, endpoint, query ) {
|
// TODO: Use controls data plugin or fresh-data instead of async
|
||||||
|
async getReportStats( ...args ) {
|
||||||
|
// This is interim code to work with either 2.x or 3.x version of @wordpress/data
|
||||||
|
// TODO: Change to just `getNotes( endpoint, query )`
|
||||||
|
// after Gutenberg plugin uses @wordpress/data 3+
|
||||||
|
const [ endpoint, query ] = args.length === 2 ? args : args.slice( 1, 3 );
|
||||||
const statEndpoints = [ 'orders', 'revenue', 'products' ];
|
const statEndpoints = [ 'orders', 'revenue', 'products' ];
|
||||||
|
|
||||||
let apiPath = endpoint + stringifyQuery( query );
|
let apiPath = endpoint + stringifyQuery( query );
|
||||||
|
|
||||||
|
// TODO: Remove once swagger endpoints are phased out.
|
||||||
|
const swaggerEndpoints = [ 'coupons', 'taxes' ];
|
||||||
|
if ( swaggerEndpoints.indexOf( endpoint ) >= 0 ) {
|
||||||
|
apiPath = SWAGGERNAMESPACE + 'reports/' + endpoint + '/stats' + stringifyQuery( query );
|
||||||
|
try {
|
||||||
|
const response = await fetch( apiPath );
|
||||||
|
|
||||||
|
const report = await response.json();
|
||||||
|
dispatch( 'wc-admin' ).setReportStats( endpoint, report, query );
|
||||||
|
} catch ( error ) {
|
||||||
|
dispatch( 'wc-admin' ).setReportStatsError( endpoint, query );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( statEndpoints.indexOf( endpoint ) >= 0 ) {
|
if ( statEndpoints.indexOf( endpoint ) >= 0 ) {
|
||||||
apiPath = NAMESPACE + 'reports/' + endpoint + '/stats' + stringifyQuery( query );
|
apiPath = NAMESPACE + 'reports/' + endpoint + '/stats' + stringifyQuery( query );
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { getJsonString } from 'store/utils';
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @param {String} endpoint Stats endpoint
|
* @param {String} endpoint Stats endpoint
|
||||||
* @param {Object} query Report query paremters
|
* @param {Object} query Report query parameters
|
||||||
* @return {Object} Report details
|
* @return {Object} Report details
|
||||||
*/
|
*/
|
||||||
function getReportStats( state, endpoint, query = {} ) {
|
function getReportStats( state, endpoint, query = {} ) {
|
||||||
|
@ -29,7 +29,7 @@ export default {
|
||||||
getReportStats,
|
getReportStats,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a stat query is pending.
|
* Returns true if a stats query is pending.
|
||||||
*
|
*
|
||||||
* @param {Object} state Current state
|
* @param {Object} state Current state
|
||||||
* @return {Boolean} True if the `getReportRevenueStats` request is pending, false otherwise
|
* @return {Boolean} True if the `getReportRevenueStats` request is pending, false otherwise
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import deepFreeze from 'deep-freeze';
|
import deepFreeze from 'deep-freeze';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { ERROR } from 'store/constants';
|
import { ERROR } from 'store/constants';
|
||||||
import selectors from '../selectors';
|
import selectors from '../selectors';
|
||||||
import { select } from '@wordpress/data';
|
|
||||||
|
|
||||||
const { getReportStats, isReportStatsRequesting, isReportStatsError } = selectors;
|
const { getReportStats, isReportStatsRequesting, isReportStatsError } = selectors;
|
||||||
jest.mock( '@wordpress/data', () => ( {
|
jest.mock( '@wordpress/data', () => ( {
|
||||||
|
|
|
@ -9,21 +9,22 @@ import { find, forEach, isNull } from 'lodash';
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { appendTimestamp, getCurrentDates, getIntervalForQuery } from '@woocommerce/date';
|
import { appendTimestamp, getCurrentDates, getIntervalForQuery } from '@woocommerce/date';
|
||||||
|
import { flattenFilters, getActiveFiltersFromQuery, getUrlKey } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { MAX_PER_PAGE } from 'store/constants';
|
import { MAX_PER_PAGE } from 'store/constants';
|
||||||
import { getActiveFiltersFromQuery, getUrlKey } from 'components/filters/advanced/utils';
|
|
||||||
import { flatenFilters } from 'components/filters/filter/utils';
|
|
||||||
import * as couponsConfig from 'analytics/report/coupons/config';
|
import * as couponsConfig from 'analytics/report/coupons/config';
|
||||||
import * as ordersConfig from 'analytics/report/orders/config';
|
import * as ordersConfig from 'analytics/report/orders/config';
|
||||||
import * as productsConfig from 'analytics/report/products/config';
|
import * as productsConfig from 'analytics/report/products/config';
|
||||||
|
import * as taxesConfig from 'analytics/report/taxes/config';
|
||||||
|
|
||||||
const reportConfigs = {
|
const reportConfigs = {
|
||||||
coupons: couponsConfig,
|
coupons: couponsConfig,
|
||||||
orders: ordersConfig,
|
orders: ordersConfig,
|
||||||
products: productsConfig,
|
products: productsConfig,
|
||||||
|
taxes: taxesConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getFilterQuery( endpoint, query ) {
|
export function getFilterQuery( endpoint, query ) {
|
||||||
|
@ -60,7 +61,7 @@ export function getQueryFromConfig( config, advancedFilters, query ) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = find( flatenFilters( config.filters ), { value: queryValue } );
|
const filter = find( flattenFilters( config.filters ), { value: queryValue } );
|
||||||
|
|
||||||
if ( ! filter ) {
|
if ( ! filter ) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/** @format */
|
/** @format */
|
||||||
|
|
||||||
|
/* stylelint-disable block-closing-brace-newline-after */
|
||||||
|
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
// Forked from https://github.com/Automattic/wp-calypso/blob/46ae24d8800fb85da6acf057a640e60dac988a38/assets/stylesheets/shared/mixins/_breakpoints.scss
|
// Forked from https://github.com/Automattic/wp-calypso/blob/46ae24d8800fb85da6acf057a640e60dac988a38/assets/stylesheets/shared/mixins/_breakpoints.scss
|
||||||
|
|
||||||
// Think very carefully before adding a new breakpoint.
|
// Think very carefully before adding a new breakpoint.
|
||||||
// The list below is based on wp-admin's main breakpoints
|
// The list below is based on wp-admin's main breakpoints
|
||||||
$breakpoints: 320px, 400px, 600px, 782px, 960px, 1100px, 1365px;
|
$breakpoints: 320px, 400px, 600px, 782px, 960px, 1280px, 1440px;
|
||||||
|
|
||||||
@mixin breakpoint( $sizes... ) {
|
@mixin breakpoint( $sizes... ) {
|
||||||
@each $size in $sizes {
|
@each $size in $sizes {
|
||||||
|
@ -44,14 +46,16 @@ $breakpoints: 320px, 400px, 600px, 782px, 960px, 1100px, 1365px;
|
||||||
@each $breakpoint in $breakpoints {
|
@each $breakpoint in $breakpoints {
|
||||||
$sizes: $sizes + ' ' + $breakpoint;
|
$sizes: $sizes + ' ' + $breakpoint;
|
||||||
}
|
}
|
||||||
@warn "ERROR in breakpoint( #{ $size } ) : You can only use these sizes[ #{$sizes} ] using the following syntax [ <#{ nth( $breakpoints, 1 ) } >#{ nth( $breakpoints, 1 ) } #{ nth( $breakpoints, 1 ) }-#{ nth( $breakpoints, 2 ) } ]";
|
@warn 'ERROR in breakpoint( #{ $size } ) : You can only use these sizes[ #{$sizes} ] using the following syntax [ <#{ nth( $breakpoints, 1 ) } >#{ nth( $breakpoints, 1 ) } #{ nth( $breakpoints, 1 ) }-#{ nth( $breakpoints, 2 ) } ]';
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
$sizes: '';
|
$sizes: '';
|
||||||
@each $breakpoint in $breakpoints {
|
@each $breakpoint in $breakpoints {
|
||||||
$sizes: $sizes + ' ' + $breakpoint;
|
$sizes: $sizes + ' ' + $breakpoint;
|
||||||
}
|
}
|
||||||
@error "ERROR in breakpoint( #{ $size } ) : Please wrap the breakpoint $size in parenthesis. You can use these sizes[ #{$sizes} ] using the following syntax [ <#{ nth( $breakpoints, 1 ) } >#{ nth( $breakpoints, 1 ) } #{ nth( $breakpoints, 1 ) }-#{ nth( $breakpoints, 2 ) } ]";
|
@error 'ERROR in breakpoint( #{ $size } ) : Please wrap the breakpoint $size in parenthesis. You can use these sizes[ #{$sizes} ] using the following syntax [ <#{ nth( $breakpoints, 1 ) } >#{ nth( $breakpoints, 1 ) } #{ nth( $breakpoints, 1 ) }-#{ nth( $breakpoints, 2 ) } ]';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stylelint-enable */
|
||||||
|
|
|
@ -23,8 +23,3 @@ $light-gray-500: $core-grey-light-500;
|
||||||
$dark-gray-300: $core-grey-dark-300;
|
$dark-gray-300: $core-grey-dark-300;
|
||||||
$dark-gray-900: $core-grey-dark-900;
|
$dark-gray-900: $core-grey-dark-900;
|
||||||
$alert-red: $error-red;
|
$alert-red: $error-red;
|
||||||
|
|
||||||
:export {
|
|
||||||
gaplarge: $gap-large;
|
|
||||||
gap: $gap;
|
|
||||||
}
|
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-top: 80px;
|
padding-top: 80px;
|
||||||
|
|
||||||
@include breakpoint( '782px-1100px' ) {
|
@include breakpoint( '782px-960px' ) {
|
||||||
padding-top: 60px;
|
padding-top: 60px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
--large-gap: 40px;
|
--large-gap: 40px;
|
||||||
--main-gap: 24px;
|
--main-gap: 24px;
|
||||||
}
|
}
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 960px) {
|
||||||
:root {
|
:root {
|
||||||
--large-gap: 24px;
|
--large-gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"squizlabs/php_codesniffer": "*",
|
"squizlabs/php_codesniffer": "*",
|
||||||
"wp-coding-standards/wpcs": "1.1.0",
|
"wp-coding-standards/wpcs": "1.2.0",
|
||||||
"phpunit/phpunit": "7.4.3",
|
"phpunit/phpunit": "6.5.13",
|
||||||
"woocommerce/woocommerce-sniffs": "*",
|
"woocommerce/woocommerce-sniffs": "*",
|
||||||
"wimg/php-compatibility": "9.0.0",
|
"wimg/php-compatibility": "9.0.0",
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "0.5.0"
|
"dealerdirect/phpcodesniffer-composer-installer": "0.5.0"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "97ef081df4492fe71d877ad105e1709b",
|
"content-hash": "8c25f2e044c24bd6ee6900e7bcbe3c0c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "composer/installers",
|
"name": "composer/installers",
|
||||||
|
@ -298,22 +298,22 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
"version": "1.0.3",
|
"version": "1.0.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phar-io/manifest.git",
|
"url": "https://github.com/phar-io/manifest.git",
|
||||||
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
|
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
|
"url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
|
||||||
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
|
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-phar": "*",
|
"ext-phar": "*",
|
||||||
"phar-io/version": "^2.0",
|
"phar-io/version": "^1.0.1",
|
||||||
"php": "^5.6 || ^7.0"
|
"php": "^5.6 || ^7.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
@ -349,20 +349,20 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||||
"time": "2018-07-08T19:23:20+00:00"
|
"time": "2017-03-05T18:14:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/version",
|
"name": "phar-io/version",
|
||||||
"version": "2.0.1",
|
"version": "1.0.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phar-io/version.git",
|
"url": "https://github.com/phar-io/version.git",
|
||||||
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
|
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
|
"url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
|
||||||
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
|
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -396,7 +396,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Library for handling version information and constraints",
|
"description": "Library for handling version information and constraints",
|
||||||
"time": "2018-07-08T19:19:57+00:00"
|
"time": "2017-03-05T17:38:23+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
|
@ -615,40 +615,40 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "6.1.3",
|
"version": "5.3.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "4d3ae9b21a7d7e440bd0cf65565533117976859f"
|
"reference": "c89677919c5dd6d3b3852f230a663118762218ac"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4d3ae9b21a7d7e440bd0cf65565533117976859f",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
|
||||||
"reference": "4d3ae9b21a7d7e440bd0cf65565533117976859f",
|
"reference": "c89677919c5dd6d3b3852f230a663118762218ac",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"php": "^7.1",
|
"php": "^7.0",
|
||||||
"phpunit/php-file-iterator": "^2.0",
|
"phpunit/php-file-iterator": "^1.4.2",
|
||||||
"phpunit/php-text-template": "^1.2.1",
|
"phpunit/php-text-template": "^1.2.1",
|
||||||
"phpunit/php-token-stream": "^3.0",
|
"phpunit/php-token-stream": "^2.0.1",
|
||||||
"sebastian/code-unit-reverse-lookup": "^1.0.1",
|
"sebastian/code-unit-reverse-lookup": "^1.0.1",
|
||||||
"sebastian/environment": "^3.1 || ^4.0",
|
"sebastian/environment": "^3.0",
|
||||||
"sebastian/version": "^2.0.1",
|
"sebastian/version": "^2.0.1",
|
||||||
"theseer/tokenizer": "^1.1"
|
"theseer/tokenizer": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.0"
|
"phpunit/phpunit": "^6.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-xdebug": "^2.6.0"
|
"ext-xdebug": "^2.5.5"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "6.1-dev"
|
"dev-master": "5.3.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -674,32 +674,29 @@
|
||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2018-10-23T05:59:32+00:00"
|
"time": "2018-04-06T15:36:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
"version": "2.0.2",
|
"version": "1.4.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||||
"reference": "050bedf145a257b1ff02746c31894800e5122946"
|
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
|
||||||
"reference": "050bedf145a257b1ff02746c31894800e5122946",
|
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1"
|
"php": ">=5.3.3"
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^7.1"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.0.x-dev"
|
"dev-master": "1.4.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -714,7 +711,7 @@
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
"email": "sebastian@phpunit.de",
|
"email": "sb@sebastian-bergmann.de",
|
||||||
"role": "lead"
|
"role": "lead"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -724,7 +721,7 @@
|
||||||
"filesystem",
|
"filesystem",
|
||||||
"iterator"
|
"iterator"
|
||||||
],
|
],
|
||||||
"time": "2018-09-13T20:33:42+00:00"
|
"time": "2017-11-27T13:52:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-text-template",
|
"name": "phpunit/php-text-template",
|
||||||
|
@ -769,28 +766,28 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-timer",
|
"name": "phpunit/php-timer",
|
||||||
"version": "2.0.0",
|
"version": "1.0.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
||||||
"reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
|
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
|
||||||
"reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
|
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1"
|
"php": "^5.3.3 || ^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.0"
|
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.0-dev"
|
"dev-master": "1.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -805,7 +802,7 @@
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
"email": "sebastian@phpunit.de",
|
"email": "sb@sebastian-bergmann.de",
|
||||||
"role": "lead"
|
"role": "lead"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -814,33 +811,33 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"timer"
|
"timer"
|
||||||
],
|
],
|
||||||
"time": "2018-02-01T13:07:23+00:00"
|
"time": "2017-02-26T11:10:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-token-stream",
|
"name": "phpunit/php-token-stream",
|
||||||
"version": "3.0.0",
|
"version": "2.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||||
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
|
"reference": "791198a2c6254db10131eecfe8c06670700904db"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
|
||||||
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
|
"reference": "791198a2c6254db10131eecfe8c06670700904db",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-tokenizer": "*",
|
"ext-tokenizer": "*",
|
||||||
"php": "^7.1"
|
"php": "^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.0"
|
"phpunit/phpunit": "^6.2.4"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.0-dev"
|
"dev-master": "2.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -863,57 +860,57 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"tokenizer"
|
"tokenizer"
|
||||||
],
|
],
|
||||||
"time": "2018-02-01T13:16:43+00:00"
|
"time": "2017-11-27T05:48:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "7.4.3",
|
"version": "6.5.13",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "c151651fb6ed264038d486ea262e243af72e5e64"
|
"reference": "0973426fb012359b2f18d3bd1e90ef1172839693"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c151651fb6ed264038d486ea262e243af72e5e64",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693",
|
||||||
"reference": "c151651fb6ed264038d486ea262e243af72e5e64",
|
"reference": "0973426fb012359b2f18d3bd1e90ef1172839693",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"doctrine/instantiator": "^1.1",
|
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"myclabs/deep-copy": "^1.7",
|
"myclabs/deep-copy": "^1.6.1",
|
||||||
"phar-io/manifest": "^1.0.2",
|
"phar-io/manifest": "^1.0.1",
|
||||||
"phar-io/version": "^2.0",
|
"phar-io/version": "^1.0",
|
||||||
"php": "^7.1",
|
"php": "^7.0",
|
||||||
"phpspec/prophecy": "^1.7",
|
"phpspec/prophecy": "^1.7",
|
||||||
"phpunit/php-code-coverage": "^6.0.7",
|
"phpunit/php-code-coverage": "^5.3",
|
||||||
"phpunit/php-file-iterator": "^2.0.1",
|
"phpunit/php-file-iterator": "^1.4.3",
|
||||||
"phpunit/php-text-template": "^1.2.1",
|
"phpunit/php-text-template": "^1.2.1",
|
||||||
"phpunit/php-timer": "^2.0",
|
"phpunit/php-timer": "^1.0.9",
|
||||||
"sebastian/comparator": "^3.0",
|
"phpunit/phpunit-mock-objects": "^5.0.9",
|
||||||
"sebastian/diff": "^3.0",
|
"sebastian/comparator": "^2.1",
|
||||||
"sebastian/environment": "^3.1 || ^4.0",
|
"sebastian/diff": "^2.0",
|
||||||
|
"sebastian/environment": "^3.1",
|
||||||
"sebastian/exporter": "^3.1",
|
"sebastian/exporter": "^3.1",
|
||||||
"sebastian/global-state": "^2.0",
|
"sebastian/global-state": "^2.0",
|
||||||
"sebastian/object-enumerator": "^3.0.3",
|
"sebastian/object-enumerator": "^3.0.3",
|
||||||
"sebastian/resource-operations": "^2.0",
|
"sebastian/resource-operations": "^1.0",
|
||||||
"sebastian/version": "^2.0.1"
|
"sebastian/version": "^2.0.1"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"phpunit/phpunit-mock-objects": "*"
|
"phpdocumentor/reflection-docblock": "3.0.2",
|
||||||
|
"phpunit/dbunit": "<3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-soap": "*",
|
|
||||||
"ext-xdebug": "*",
|
"ext-xdebug": "*",
|
||||||
"phpunit/php-invoker": "^2.0"
|
"phpunit/php-invoker": "^1.1"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"phpunit"
|
"phpunit"
|
||||||
|
@ -921,7 +918,7 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "7.4-dev"
|
"dev-master": "6.5.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -947,7 +944,66 @@
|
||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2018-10-23T05:57:41+00:00"
|
"time": "2018-09-08T15:10:43+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "phpunit/phpunit-mock-objects",
|
||||||
|
"version": "5.0.10",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
|
||||||
|
"reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f",
|
||||||
|
"reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/instantiator": "^1.0.5",
|
||||||
|
"php": "^7.0",
|
||||||
|
"phpunit/php-text-template": "^1.2.1",
|
||||||
|
"sebastian/exporter": "^3.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpunit/phpunit": "<6.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.5.11"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-soap": "*"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Sebastian Bergmann",
|
||||||
|
"email": "sebastian@phpunit.de",
|
||||||
|
"role": "lead"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Mock Object library for PHPUnit",
|
||||||
|
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
|
||||||
|
"keywords": [
|
||||||
|
"mock",
|
||||||
|
"xunit"
|
||||||
|
],
|
||||||
|
"time": "2018-08-09T05:50:03+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/code-unit-reverse-lookup",
|
"name": "sebastian/code-unit-reverse-lookup",
|
||||||
|
@ -996,30 +1052,30 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/comparator",
|
"name": "sebastian/comparator",
|
||||||
"version": "3.0.2",
|
"version": "2.1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||||
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
|
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
|
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
|
||||||
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
|
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1",
|
"php": "^7.0",
|
||||||
"sebastian/diff": "^3.0",
|
"sebastian/diff": "^2.0 || ^3.0",
|
||||||
"sebastian/exporter": "^3.1"
|
"sebastian/exporter": "^3.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.1"
|
"phpunit/phpunit": "^6.4"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.0-dev"
|
"dev-master": "2.1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -1056,33 +1112,32 @@
|
||||||
"compare",
|
"compare",
|
||||||
"equality"
|
"equality"
|
||||||
],
|
],
|
||||||
"time": "2018-07-12T15:12:46+00:00"
|
"time": "2018-02-01T13:46:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
"version": "3.0.1",
|
"version": "2.0.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||||
"reference": "366541b989927187c4ca70490a35615d3fef2dce"
|
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce",
|
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
|
||||||
"reference": "366541b989927187c4ca70490a35615d3fef2dce",
|
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1"
|
"php": "^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.0",
|
"phpunit/phpunit": "^6.2"
|
||||||
"symfony/process": "^2 || ^3.3 || ^4"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.0-dev"
|
"dev-master": "2.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -1107,12 +1162,9 @@
|
||||||
"description": "Diff implementation",
|
"description": "Diff implementation",
|
||||||
"homepage": "https://github.com/sebastianbergmann/diff",
|
"homepage": "https://github.com/sebastianbergmann/diff",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"diff",
|
"diff"
|
||||||
"udiff",
|
|
||||||
"unidiff",
|
|
||||||
"unified diff"
|
|
||||||
],
|
],
|
||||||
"time": "2018-06-10T07:54:39+00:00"
|
"time": "2017-08-03T08:09:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/environment",
|
"name": "sebastian/environment",
|
||||||
|
@ -1429,25 +1481,25 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/resource-operations",
|
"name": "sebastian/resource-operations",
|
||||||
"version": "2.0.1",
|
"version": "1.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
||||||
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
|
"reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
|
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
|
||||||
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
|
"reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1"
|
"php": ">=5.6.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.0-dev"
|
"dev-master": "1.0.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -1467,7 +1519,7 @@
|
||||||
],
|
],
|
||||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||||
"time": "2018-10-04T04:07:39+00:00"
|
"time": "2015-07-28T20:34:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/version",
|
"name": "sebastian/version",
|
||||||
|
@ -1713,24 +1765,23 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "woocommerce/woocommerce-sniffs",
|
"name": "woocommerce/woocommerce-sniffs",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
|
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
|
||||||
"reference": "2890fd5d98b318f62acb42f2b5cd6d02627cfd82"
|
"reference": "c7e6e641e47b397ee64eb52a762c265cf476495a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/2890fd5d98b318f62acb42f2b5cd6d02627cfd82",
|
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/c7e6e641e47b397ee64eb52a762c265cf476495a",
|
||||||
"reference": "2890fd5d98b318f62acb42f2b5cd6d02627cfd82",
|
"reference": "c7e6e641e47b397ee64eb52a762c265cf476495a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
|
||||||
"php": ">=7.0",
|
"php": ">=7.0",
|
||||||
"squizlabs/php_codesniffer": "^3.0.2"
|
"wimg/php-compatibility": "^9.0",
|
||||||
},
|
"wp-coding-standards/wpcs": "^1.1"
|
||||||
"suggest": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
|
|
||||||
},
|
},
|
||||||
"type": "phpcodesniffer-standard",
|
"type": "phpcodesniffer-standard",
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
@ -1750,20 +1801,20 @@
|
||||||
"woocommerce",
|
"woocommerce",
|
||||||
"wordpress"
|
"wordpress"
|
||||||
],
|
],
|
||||||
"time": "2018-03-22T18:39:19+00:00"
|
"time": "2018-11-06T22:51:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wp-coding-standards/wpcs",
|
"name": "wp-coding-standards/wpcs",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
|
"url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
|
||||||
"reference": "46d42828ce7355d8b3776e3171f2bda892d179b4"
|
"reference": "7aa217ab38156c5cb4eae0f04ae376027c407a9b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/46d42828ce7355d8b3776e3171f2bda892d179b4",
|
"url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/7aa217ab38156c5cb4eae0f04ae376027c407a9b",
|
||||||
"reference": "46d42828ce7355d8b3776e3171f2bda892d179b4",
|
"reference": "7aa217ab38156c5cb4eae0f04ae376027c407a9b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1771,7 +1822,7 @@
|
||||||
"squizlabs/php_codesniffer": "^2.9.0 || ^3.0.2"
|
"squizlabs/php_codesniffer": "^2.9.0 || ^3.0.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpcompatibility/php-compatibility": "*"
|
"phpcompatibility/php-compatibility": "^9.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
||||||
|
@ -1793,7 +1844,7 @@
|
||||||
"standards",
|
"standards",
|
||||||
"wordpress"
|
"wordpress"
|
||||||
],
|
],
|
||||||
"time": "2018-09-10T17:04:05+00:00"
|
"time": "2018-11-12T10:13:12+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
* [Data](data)
|
* [Data](data)
|
||||||
* [Layout](layout)
|
* [Layout](layout)
|
||||||
* [CSS Structure](stylesheets)
|
* [CSS Structure](stylesheets)
|
||||||
|
* [Examples](examples/)
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
* [ProductImage](components/product-image.md)
|
* [ProductImage](components/product-image.md)
|
||||||
* [Rating](components/rating.md)
|
* [Rating](components/rating.md)
|
||||||
* [Search](components/search.md)
|
* [Search](components/search.md)
|
||||||
|
* [SectionHeader](components/section-header.md)
|
||||||
* [Section](components/section.md)
|
* [Section](components/section.md)
|
||||||
* [SegmentedSelection](components/segmented-selection.md)
|
* [SegmentedSelection](components/segmented-selection.md)
|
||||||
* [SplitButton](components/split-button.md)
|
* [SplitButton](components/split-button.md)
|
||||||
* [Summary](components/summary.md)
|
* [Summary](components/summary.md)
|
||||||
* [Table](components/table.md)
|
* [Table](components/table.md)
|
||||||
* [Tag](components/tag.md)
|
* [Tag](components/tag.md)
|
||||||
|
* [ViewMoreList](components/view-more-list.md)
|
||||||
|
|
|
@ -29,7 +29,6 @@ An `EllipsisMenu`, with filters used to control the content visible in this card
|
||||||
|
|
||||||
### `title`
|
### `title`
|
||||||
|
|
||||||
- **Required**
|
|
||||||
- Type: One of type: string, node
|
- Type: One of type: string, node
|
||||||
- Default: null
|
- Default: null
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue