diff --git a/plugins/woocommerce-admin/bin/generate-docs/index.js b/plugins/woocommerce-admin/bin/generate-docs/index.js index 6715e271cd8..1dad2018b15 100755 --- a/plugins/woocommerce-admin/bin/generate-docs/index.js +++ b/plugins/woocommerce-admin/bin/generate-docs/index.js @@ -12,45 +12,82 @@ const { parse, resolver } = require( 'react-docgen' ); */ const { getDescription, getProps, getTitle } = require( './lib/formatting' ); const { + ANALYTICS_FOLDER, PACKAGES_FOLDER, + DOCS_FOLDER, deleteExistingDocs, getExportedFileList, getMdFileName, getRealFilePaths, - writeTableOfContents, + getTocSection, } = require( './lib/file-system' ); -// Start by wiping the existing docs. **Change this if we end up manually editing docs** -deleteExistingDocs(); - -// 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( path.resolve( PACKAGES_FOLDER, 'index.js' ) ), PACKAGES_FOLDER ), +const fileCollections = [ + { + folder: ANALYTICS_FOLDER, + route: 'analytics', + title: 'Analytics components', + }, + { + folder: PACKAGES_FOLDER, + route: 'packages', + title: 'Package components', + }, ]; -// Build the documentation by reading each file. -files.forEach( file => { - try { - const content = fs.readFileSync( file ); - buildDocs( file, content ); - } catch ( readErr ) { - console.warn( file, readErr ); - } +const tocSections = []; + +fileCollections.forEach( fileCollection => { + // Start by wiping the existing docs. **Change this if we end up manually editing docs** + deleteExistingDocs( fileCollection.route ); + + // 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( path.resolve( fileCollection.folder, 'index.js' ) ), fileCollection.folder ); + + // Build documentation + buildComponentDocs( files, fileCollection.route ); + + // Concatenate TOC contents + tocSections.push( ...getTocSection( files, fileCollection.route, fileCollection.title ) ); } ); -writeTableOfContents( files ); +// Write TOC file +const tocFile = path.resolve( DOCS_FOLDER, '_sidebar.md' ); +const tocHeader = '* [Home](/)\n\n* [Components](components/)\n\n'; +fs.writeFileSync( tocFile, tocHeader + tocSections.join( '\n' ) ); -console.log( `Wrote docs for ${ files.length } files.` ); +// Sum the number of TOC lines and substract the titles +const numberOfFiles = tocSections.length - fileCollections.length; +console.log( `Wrote docs for ${ numberOfFiles } files.` ); + +/** + * Parse each file's content & build up a markdown file. + * + * @param { Array } files The absolute path of this file. + * @param { string } route Folder where the docs must be stored. + */ +function buildComponentDocs( files, route ) { + // Build the documentation by reading each file. + files.forEach( file => { + try { + const content = fs.readFileSync( file ); + buildDocs( file, route, content ); + } catch ( readErr ) { + console.warn( file, readErr ); + } + } ); +} /** * Parse each file's content & build up a markdown file. * * @param { string } fileName The absolute path of this file. + * @param { string } route Folder where the docs must be stored. * @param { string } content Content of this file. * @param { boolean } multiple If there are multiple exports in this file, we need to use a different resolver. */ -function buildDocs( fileName, content, multiple = false ) { - const mdFileName = getMdFileName( fileName ); +function buildDocs( fileName, route, content, multiple = false ) { + const mdFileName = getMdFileName( fileName, route ); let markdown; try { @@ -65,7 +102,7 @@ function buildDocs( fileName, content, multiple = false ) { } catch ( parseErr ) { if ( ! multiple ) { // The most likely error is that there are multiple exported components - buildDocs( fileName, content, true ); + buildDocs( fileName, route, content, true ); return; } console.warn( fileName, parseErr ); diff --git a/plugins/woocommerce-admin/bin/generate-docs/lib/file-system.js b/plugins/woocommerce-admin/bin/generate-docs/lib/file-system.js index a4ff6ac961a..20fcad5e392 100644 --- a/plugins/woocommerce-admin/bin/generate-docs/lib/file-system.js +++ b/plugins/woocommerce-admin/bin/generate-docs/lib/file-system.js @@ -14,24 +14,28 @@ const { namedTypes } = types; */ const { camelCaseDash } = require( './formatting' ); +const ANALYTICS_FOLDER = path.resolve( __dirname, '../../../client/analytics/components/' ); const PACKAGES_FOLDER = path.resolve( __dirname, '../../../packages/components/src/' ); const DOCS_FOLDER = path.resolve( __dirname, '../../../docs/components/' ); /** * Remove all files in existing docs folder. + * @param { String } route Route of the folder to clean. */ -function deleteExistingDocs() { - if ( ! isDirectory( DOCS_FOLDER ) ) { - fs.mkdirSync( DOCS_FOLDER ); +function deleteExistingDocs( route ) { + const folderRoute = path.resolve( DOCS_FOLDER, route ); + + if ( ! isDirectory( folderRoute ) ) { + fs.mkdirSync( folderRoute ); return; } - const files = fs.readdirSync( DOCS_FOLDER ); + const files = fs.readdirSync( folderRoute ); files.map( file => { if ( 'README.md' === file ) { return; } - fs.unlinkSync( path.resolve( DOCS_FOLDER, file ) ); + fs.unlinkSync( path.resolve( folderRoute, file ) ); } ); } @@ -70,10 +74,11 @@ function getExportedFileList( filePath ) { * Return the markdown file name for a given component file. * * @param { string } filepath File path for this component. + * @param { string } route Folder where the docs must be stored. * @param { boolean } absolute Whether to return full path (true) or just filename (false). * @return { string } Markdown file name. */ -function getMdFileName( filepath, absolute = true ) { +function getMdFileName( filepath, route, absolute = true ) { const fileParts = filepath.split( '/components/' ); if ( ! fileParts || ! fileParts[ 1 ] ) { return; @@ -82,7 +87,7 @@ function getMdFileName( filepath, absolute = true ) { if ( ! absolute ) { return name + '.md'; } - return path.resolve( DOCS_FOLDER, name + '.md' ); + return path.resolve( DOCS_FOLDER + '/' + route + '/', name + '.md' ); } /** @@ -145,25 +150,32 @@ function isFile( file ) { /** * Create a table of contents given a list of markdown files. * - * @param { array } files A list of readme files. + * @param { array } files A list of files, presumably in the components directory. + * @param { string } route Folder where the docs are stored. + * @param { string } title Title of the TOC section + * @return { string } TOC contents. */ -function writeTableOfContents( files ) { - const mdFiles = files.map( f => getMdFileName( f, false ) ).sort(); - const TOC = uniq( mdFiles ).map( doc => { - const name = camelCaseDash( doc.replace( '.md', '' ) ); - return ` * [${ name }](components/${ doc })`; - } ).join( '\n' ); +function getTocSection( files, route, title ) { + const mdFiles = files.map( f => getMdFileName( f, route, false ) ).sort(); - const TocFile = path.resolve( DOCS_FOLDER, '_sidebar.md' ); - fs.writeFileSync( TocFile, '* [Home](/)\n\n* [Components](components/)\n\n' + TOC + '\n' ); + const toc = uniq( mdFiles ).map( doc => { + const name = camelCaseDash( doc.replace( '.md', '' ) ); + return ` * [${ name }](components/${ route }/${ doc })`; + } ); + + return [ + ' * [' + title + '](components/' + route + '/)', + ...toc, + ]; } module.exports = { DOCS_FOLDER, + ANALYTICS_FOLDER, PACKAGES_FOLDER, deleteExistingDocs, getExportedFileList, getMdFileName, getRealFilePaths, - writeTableOfContents, + getTocSection, }; diff --git a/plugins/woocommerce-admin/bin/packages/post-css-config.js b/plugins/woocommerce-admin/bin/packages/post-css-config.js index 073cb000156..67caa18d3d0 100644 --- a/plugins/woocommerce-admin/bin/packages/post-css-config.js +++ b/plugins/woocommerce-admin/bin/packages/post-css-config.js @@ -17,6 +17,6 @@ module.exports = [ }, }, } ), - require( 'autoprefixer' ), + require( 'autoprefixer' )( { grid: true } ), require( 'postcss-color-function' ), ]; diff --git a/plugins/woocommerce-admin/client/analytics/components/index.js b/plugins/woocommerce-admin/client/analytics/components/index.js new file mode 100644 index 00000000000..a19a6f32281 --- /dev/null +++ b/plugins/woocommerce-admin/client/analytics/components/index.js @@ -0,0 +1,6 @@ +/** @format */ + +export { default as ReportChart } from './report-chart'; +export { default as ReportError } from './report-error'; +export { default as ReportSummary } from './report-summary'; +export { default as ReportTable } from './report-table'; diff --git a/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js b/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js index 85f991720f7..89d468bfbf3 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js @@ -31,6 +31,9 @@ import withSelect from 'wc-api/with-select'; export const DEFAULT_FILTER = 'all'; +/** + * Component that renders the chart in reports. + */ export class ReportChart extends Component { getSelectedFilter( filters, query ) { if ( filters.length === 0 ) { @@ -65,7 +68,7 @@ export class ReportChart extends Component { } render() { - const { query, itemsLabel, path, primaryData, secondaryData, selectedChart } = this.props; + const { query, itemsLabel, mode, path, primaryData, secondaryData, selectedChart } = this.props; if ( primaryData.isError || secondaryData.isError ) { return ; @@ -80,7 +83,7 @@ export class ReportChart extends Component { const chartData = primaryData.data.intervals.map( function( interval, index ) { const secondaryDate = getPreviousDate( - formatDate( 'Y-m-d', interval.date_start ), + interval.date_start, primary.after, secondary.after, query.compare, @@ -111,7 +114,7 @@ export class ReportChart extends Component { type={ getChartTypeForQuery( query ) } allowedIntervals={ allowedIntervals } itemsLabel={ itemsLabel } - mode={ this.getChartMode() } + mode={ mode || this.getChartMode() } tooltipLabelFormat={ formats.tooltipLabelFormat } tooltipValueFormat={ getTooltipValueFormat( selectedChart.type ) } tooltipTitle={ selectedChart.label } @@ -126,12 +129,38 @@ export class ReportChart extends Component { } ReportChart.propTypes = { + /** + * Filters available for that report. + */ filters: PropTypes.array, + /** + * Label describing the legend items. + */ itemsLabel: PropTypes.string, + /** + * `items-comparison` (default) or `time-comparison`, this is used to generate correct + * ARIA properties. + */ + mode: PropTypes.string, + /** + * Current path + */ path: PropTypes.string.isRequired, + /** + * Primary data to display in the chart. + */ primaryData: PropTypes.object.isRequired, + /** + * The query string represented in object form. + */ query: PropTypes.object.isRequired, + /** + * Secondary data to display in the chart. + */ secondaryData: PropTypes.object.isRequired, + /** + * Properties of the selected chart. + */ selectedChart: PropTypes.object.isRequired, }; diff --git a/plugins/woocommerce-admin/client/analytics/components/report-error/index.js b/plugins/woocommerce-admin/client/analytics/components/report-error/index.js index ea17d7438c2..136fa254e0c 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-error/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-error/index.js @@ -12,6 +12,10 @@ import PropTypes from 'prop-types'; import { EmptyContent } from '@woocommerce/components'; import { getAdminLink } from '@woocommerce/navigation'; +/** + * Component to render when there is an error in a report component due to data + * not being loaded or being invalid. + */ class ReportError extends Component { render() { const { className, isError, isEmpty } = this.props; @@ -42,8 +46,17 @@ class ReportError extends Component { } ReportError.propTypes = { + /** + * Additional class name to style the component. + */ className: PropTypes.string, + /** + * Boolean representing whether there was an error. + */ isError: PropTypes.bool, + /** + * Boolean representing whether the issue is that there is no data. + */ isEmpty: PropTypes.bool, }; diff --git a/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js b/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js index 22a127cdcfb..fc59ca361d1 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js @@ -22,6 +22,9 @@ import ReportError from 'analytics/components/report-error'; import { calculateDelta, formatValue } from './utils'; import withSelect from 'wc-api/with-select'; +/** + * Component to render summary numbers in reports. + */ export class ReportSummary extends Component { render() { const { charts, query, selectedChart, summaryData } = this.props; @@ -70,10 +73,30 @@ export class ReportSummary extends Component { } ReportSummary.propTypes = { + /** + * Properties of all the charts available for that report. + */ charts: PropTypes.array.isRequired, + /** + * The endpoint to use in API calls to populate the Summary Numbers. + * For example, if `taxes` is provided, data will be fetched from the report + * `taxes` endpoint (ie: `/wc/v3/reports/taxes/stats`). If the provided endpoint + * doesn't exist, an error will be shown to the user with `ReportError`. + */ endpoint: PropTypes.string.isRequired, + /** + * The query string represented in object form. + */ query: PropTypes.object.isRequired, - selectedChart: PropTypes.object.isRequired, + /** + * Properties of the selected chart. + */ + selectedChart: PropTypes.shape( { + /** + * Key of the selected chart. + */ + key: PropTypes.string.isRequired, + } ).isRequired, }; export default compose( diff --git a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js index 9756aa57ed6..e014003eebd 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js @@ -25,28 +25,39 @@ import { extendTableData } from './utils'; const TABLE_FILTER = 'woocommerce_admin_report_table'; +/** + * Component that extends `TableCard` to facilitate its usage in reports. + */ class ReportTable extends Component { - onColumnsChange = columns => { - const { columnPrefsKey } = this.props; + constructor( props ) { + super( props ); + + this.onColumnsChange = this.onColumnsChange.bind( this ); + } + + onColumnsChange( shownColumns ) { + const { columnPrefsKey, getHeadersContent } = this.props; + const columns = getHeadersContent().map( header => header.key ); + const hiddenColumns = columns.filter( column => ! shownColumns.includes( column ) ); if ( columnPrefsKey ) { const userDataFields = { - [ columnPrefsKey ]: columns, + [ columnPrefsKey ]: hiddenColumns, }; this.props.updateCurrentUserData( userDataFields ); } - }; + } - filterShownHeaders = ( headers, shownKeys ) => { - if ( ! shownKeys ) { + filterShownHeaders( headers, hiddenKeys ) { + if ( ! hiddenKeys ) { return headers; } return headers.map( header => { - const hidden = ! shownKeys.includes( header.key ); + const hidden = hiddenKeys.includes( header.key ) && ! header.required; return { ...header, hiddenByDefault: hidden }; } ); - }; + } render() { const { @@ -56,7 +67,7 @@ class ReportTable extends Component { itemIdField, primaryData, tableData, - // These two props are not used in the render function, but are destructured + // These props are not used in the render function, but are destructured // so they are not included in the `tableProps` variable. endpoint, tableQuery, @@ -113,7 +124,11 @@ ReportTable.propTypes = { */ columnPrefsKey: PropTypes.string, /** - * The endpoint to use in API calls. + * The endpoint to use in API calls to populate the table rows and summary. + * For example, if `taxes` is provided, data will be fetched from the report + * `taxes` endpoint (ie: `/wc/v3/reports/taxes` and `/wc/v3/reports/taxes/stats`). + * If the provided endpoint doesn't exist, an error will be shown to the user + * with `ReportError`. */ endpoint: PropTypes.string, /** @@ -143,11 +158,13 @@ ReportTable.propTypes = { */ itemIdField: PropTypes.string, /** - * Primary data of that report. + * Primary data of that report. If it's not provided, it will be automatically + * loaded via the provided `endpoint`. */ primaryData: PropTypes.object.isRequired, /** - * Table data of that report. + * Table data of that report. If it's not provided, it will be automatically + * loaded via the provided `endpoint`. */ tableData: PropTypes.object.isRequired, /** diff --git a/plugins/woocommerce-admin/client/analytics/report/categories/breadcrumbs.js b/plugins/woocommerce-admin/client/analytics/report/categories/breadcrumbs.js new file mode 100644 index 00000000000..544434dc4a1 --- /dev/null +++ b/plugins/woocommerce-admin/client/analytics/report/categories/breadcrumbs.js @@ -0,0 +1,67 @@ +/** @format */ +/** + * External dependencies + */ +import { Component } from '@wordpress/element'; +import { first, last } from 'lodash'; +import { Spinner } from '@wordpress/components'; + +/** + * WooCommerce dependencies + */ +import { Link } from '@woocommerce/components'; + +export default class CategoryBreadcrumbs extends Component { + getCategoryAncestorIds( category, categories ) { + const ancestors = []; + let parent = category.parent; + while ( parent ) { + ancestors.unshift( parent ); + parent = categories[ parent ].parent; + } + return ancestors; + } + + getCategoryAncestors( category, categories ) { + const ancestorIds = this.getCategoryAncestorIds( category, categories ); + + if ( ! ancestorIds.length ) { + return; + } + if ( ancestorIds.length === 1 ) { + return categories[ first( ancestorIds ) ].name + ' › '; + } + if ( ancestorIds.length === 2 ) { + return ( + categories[ first( ancestorIds ) ].name + + ' › ' + + categories[ last( ancestorIds ) ].name + + ' › ' + ); + } + return ( + categories[ first( ancestorIds ) ].name + + ' … ' + + categories[ last( ancestorIds ) ].name + + ' › ' + ); + } + + render() { + const { categories, category } = this.props; + + return category ? ( +
+ { this.getCategoryAncestors( category, categories ) } + + { category.name } + +
+ ) : ( + + ); + } +} diff --git a/plugins/woocommerce-admin/client/analytics/report/categories/config.js b/plugins/woocommerce-admin/client/analytics/report/categories/config.js index b6a57a79929..047d5c04561 100644 --- a/plugins/woocommerce-admin/client/analytics/report/categories/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/categories/config.js @@ -4,6 +4,12 @@ */ import { __ } from '@wordpress/i18n'; +/** + * Internal dependencies + */ +import { getRequestByIdString } from 'lib/async-requests'; +import { NAMESPACE } from 'store/constants'; + export const charts = [ { key: 'items_sold', @@ -30,7 +36,37 @@ export const filters = [ showFilters: () => true, filters: [ { label: __( 'All Categories', 'wc-admin' ), value: 'all' }, - { label: __( 'Advanced Filters', 'wc-admin' ), value: 'advanced' }, + { + label: __( 'Comparison', 'wc-admin' ), + value: 'compare-categories', + chartMode: 'item-comparison', + settings: { + type: 'categories', + param: 'categories', + getLabels: getRequestByIdString( NAMESPACE + 'products/categories', cat => ( { + id: cat.id, + label: cat.name, + } ) ), + labels: { + helpText: __( 'Select at least two categories to compare', 'wc-admin' ), + placeholder: __( 'Search for categories to compare', 'wc-admin' ), + title: __( 'Compare Categories', 'wc-admin' ), + update: __( 'Compare', 'wc-admin' ), + }, + }, + }, + { + label: __( 'Top Categories by Items Sold', 'wc-admin' ), + value: 'top_items', + chartMode: 'item-comparison', + query: { orderby: 'items_sold', order: 'desc' }, + }, + { + label: __( 'Top Categories by Net Revenue', 'wc-admin' ), + value: 'top_revenue', + chartMode: 'item-comparison', + query: { orderby: 'net_revenue', order: 'desc' }, + }, ], }, ]; diff --git a/plugins/woocommerce-admin/client/analytics/report/categories/table.js b/plugins/woocommerce-admin/client/analytics/report/categories/table.js index 8eb3632b8ce..5b4b19791a8 100644 --- a/plugins/woocommerce-admin/client/analytics/report/categories/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/categories/table.js @@ -4,21 +4,23 @@ */ import { __, _n } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; +import { compose } from '@wordpress/compose'; import { map } from 'lodash'; /** * WooCommerce dependencies */ -import { Link } from '@woocommerce/components'; import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency'; /** * Internal dependencies */ -import ReportTable from 'analytics/components/report-table'; +import CategoryBreacrumbs from './breadcrumbs'; import { numberFormat } from 'lib/number'; +import ReportTable from 'analytics/components/report-table'; +import withSelect from 'wc-api/with-select'; -export default class CategoriesReportTable extends Component { +class CategoriesReportTable extends Component { constructor( props ) { super( props ); @@ -32,7 +34,6 @@ export default class CategoriesReportTable extends Component { key: 'category', required: true, isLeftAligned: true, - isSortable: true, }, { label: __( 'Items sold', 'wc-admin' ), @@ -43,8 +44,7 @@ export default class CategoriesReportTable extends Component { isNumeric: true, }, { - label: __( 'G. Revenue', 'wc-admin' ), - screenReaderLabel: __( 'Gross Revenue', 'wc-admin' ), + label: __( 'Net Revenue', 'wc-admin' ), key: 'net_revenue', isSortable: true, isNumeric: true, @@ -64,29 +64,16 @@ export default class CategoriesReportTable extends Component { ]; } - getRowsContent( categories ) { - return map( categories, category => { - const { - category_id, - items_sold, - net_revenue, - products_count, - orders_count, - extended_info, - } = category; - const { name } = extended_info; + getRowsContent( categoryStats ) { + return map( categoryStats, categoryStat => { + const { category_id, items_sold, net_revenue, products_count, orders_count } = categoryStat; + const categories = this.props.categories; + const category = categories[ category_id ]; return [ { - display: ( - - { name } - - ), - value: name, + display: , + value: category && category.name, }, { display: numberFormat( items_sold ), @@ -136,15 +123,21 @@ export default class CategoriesReportTable extends Component { render() { const { query } = this.props; + const labels = { + helpText: __( 'Select at least two categories to compare', 'wc-admin' ), + placeholder: __( 'Search by category name', 'wc-admin' ), + }; + return ( { + const { getCategories, getCategoriesError, isGetCategoriesRequesting } = select( 'wc-api' ); + const tableQuery = { + per_page: -1, + }; + + const categories = getCategories( tableQuery ); + const isError = Boolean( getCategoriesError( tableQuery ) ); + const isRequesting = isGetCategoriesRequesting( tableQuery ); + + return { categories, isError, isRequesting }; + } ) +)( CategoriesReportTable ); diff --git a/plugins/woocommerce-admin/client/analytics/report/coupons/config.js b/plugins/woocommerce-admin/client/analytics/report/coupons/config.js index 6f532325e0e..fdc957146cc 100644 --- a/plugins/woocommerce-admin/client/analytics/report/coupons/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/coupons/config.js @@ -12,13 +12,13 @@ import { NAMESPACE } from 'store/constants'; export const charts = [ { - key: 'discounted_orders', + key: 'orders_count', label: __( 'Discounted Orders', 'wc-admin' ), type: 'number', }, { - key: 'coupons', - label: __( 'Gross Discounted', 'wc-admin' ), + key: 'amount', + label: __( 'Amount', 'wc-admin' ), type: 'currency', }, ]; @@ -48,7 +48,7 @@ export const filters = [ }, }, { label: __( 'Top Coupons by Discounted Orders', 'wc-admin' ), value: 'top_orders' }, - { label: __( 'Top Coupons by Gross Discounted', 'wc-admin' ), value: 'top_discount' }, + { label: __( 'Top Coupons by Amount Discounted', 'wc-admin' ), value: 'top_discount' }, ], }, ]; diff --git a/plugins/woocommerce-admin/client/analytics/report/coupons/index.js b/plugins/woocommerce-admin/client/analytics/report/coupons/index.js index 0078c34c5a0..113c2c45457 100644 --- a/plugins/woocommerce-admin/client/analytics/report/coupons/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/coupons/index.js @@ -28,13 +28,13 @@ export default class CouponsReport extends Component { { - const { coupon_id, gross_discount, orders_count } = coupon; + const { amount, coupon_id, extended_info, orders_count } = coupon; + const { code, date_created, date_expires, discount_type } = extended_info; // @TODO must link to the coupon detail report const couponLink = ( - { coupon_id } + { code } ); @@ -97,33 +92,29 @@ export default class CouponsReportTable extends Component { ); return [ - // @TODO it should be the coupon code, not the coupon ID { display: couponLink, - value: coupon_id, + value: code, }, { display: ordersLink, value: orders_count, }, { - display: formatCurrency( gross_discount ), - value: getCurrencyFormatDecimal( gross_discount ), + display: formatCurrency( amount ), + value: getCurrencyFormatDecimal( amount ), }, { - // @TODO - display: formatDate( tableFormat, '' ), - value: '', + display: formatDate( tableFormat, date_created ), + value: date_created, }, { - // @TODO - display: formatDate( tableFormat, '' ), - value: '', + display: date_expires ? formatDate( tableFormat, date_expires ) : __( 'N/A', 'wc-admin' ), + value: date_expires, }, { - // @TODO - display: '', - value: '', + display: this.getCouponType( discount_type ), + value: discount_type, }, ]; } ); @@ -143,12 +134,21 @@ export default class CouponsReportTable extends Component { value: numberFormat( totals.orders_count ), }, { - label: __( 'gross discounted', 'wc-admin' ), - value: formatCurrency( totals.gross_discount ), + label: __( 'amount discounted', 'wc-admin' ), + value: formatCurrency( totals.amount ), }, ]; } + getCouponType( discount_type ) { + const couponTypes = { + percent: __( 'Percentage', 'wc-admin' ), + fixed_cart: __( 'Fixed cart', 'wc-admin' ), + fixed_product: __( 'Fixed product', 'wc-admin' ), + }; + return couponTypes[ discount_type ]; + } + render() { const { query } = this.props; @@ -161,6 +161,11 @@ export default class CouponsReportTable extends Component { getSummary={ this.getSummary } itemIdField="coupon_id" query={ query } + tableQuery={ { + orderby: query.orderby || 'coupon_id', + order: query.order || 'asc', + extended_info: true, + } } title={ __( 'Coupons', 'wc-admin' ) } columnPrefsKey="coupons_report_columns" /> diff --git a/plugins/woocommerce-admin/client/analytics/report/customers/config.js b/plugins/woocommerce-admin/client/analytics/report/customers/config.js index 5f5055234c7..181f776b911 100644 --- a/plugins/woocommerce-admin/client/analytics/report/customers/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/customers/config.js @@ -166,6 +166,91 @@ export const advancedFilters = { } ) ), }, }, + order_count: { + labels: { + add: __( 'No. of Orders', 'wc-admin' ), + remove: __( 'Remove order filter', 'wc-admin' ), + rule: __( 'Select an order count filter match', 'wc-admin' ), + title: __( 'No. of Orders {{rule /}} {{filter /}}', 'wc-admin' ), + }, + rules: [ + { + value: 'max', + /* translators: Sentence fragment, logical, "Less Than" refers to number of orders a customer has placed, less than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Less Than', 'number of orders', 'wc-admin' ), + }, + { + value: 'min', + /* translators: Sentence fragment, logical, "More Than" refers to number of orders a customer has placed, more than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'More Than', 'number of orders', 'wc-admin' ), + }, + { + value: 'between', + /* translators: Sentence fragment, logical, "Between" refers to number of orders a customer has placed, between two given integers. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Between', 'number of orders', 'wc-admin' ), + }, + ], + input: { + component: 'Number', + }, + }, + total_spend: { + labels: { + add: __( 'Total Spend', 'wc-admin' ), + remove: __( 'Remove total spend filter', 'wc-admin' ), + rule: __( 'Select a total spend filter match', 'wc-admin' ), + title: __( 'Total Spend {{rule /}} {{filter /}}', 'wc-admin' ), + }, + rules: [ + { + value: 'max', + /* translators: Sentence fragment, logical, "Less Than" refers to total spending by a customer, less than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Less Than', 'total spend by customer', 'wc-admin' ), + }, + { + value: 'min', + /* translators: Sentence fragment, logical, "Less Than" refers to total spending by a customer, more than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'More Than', 'total spend by customer', 'wc-admin' ), + }, + { + value: 'between', + /* translators: Sentence fragment, logical, "Between" refers to total spending by a customer, between two given amounts. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Between', 'total spend by customer', 'wc-admin' ), + }, + ], + input: { + component: 'Currency', + }, + }, + avg_order_value: { + labels: { + add: __( 'AOV', 'wc-admin' ), + remove: __( 'Remove average older value filter', 'wc-admin' ), + rule: __( 'Select an average order value filter match', 'wc-admin' ), + title: __( 'AOV {{rule /}} {{filter /}}', 'wc-admin' ), + }, + rules: [ + { + value: 'max', + /* translators: Sentence fragment, logical, "Less Than" refers to average order value of a customer, more than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Less Than', 'average order value of customer', 'wc-admin' ), + }, + { + value: 'min', + /* translators: Sentence fragment, logical, "Less Than" refers to average order value of a customer, less than a given amount. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + + label: _x( 'More Than', 'average order value of customer', 'wc-admin' ), + }, + { + value: 'between', + /* translators: Sentence fragment, logical, "Between" refers to average order value of a customer, between two given amounts. Screenshot for context: https://cloudup.com/cCsm3GeXJbE */ + label: _x( 'Between', 'average order value of customer', 'wc-admin' ), + }, + ], + input: { + component: 'Currency', + }, + }, }, }; /*eslint-enable max-len*/ diff --git a/plugins/woocommerce-admin/client/analytics/report/downloads/config.js b/plugins/woocommerce-admin/client/analytics/report/downloads/config.js index 2181cd87f13..12a86982a6e 100644 --- a/plugins/woocommerce-admin/client/analytics/report/downloads/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/downloads/config.js @@ -70,6 +70,104 @@ export const advancedFilters = { } ) ), }, }, + username: { + labels: { + add: __( 'Username', 'wc-admin' ), + placeholder: __( 'Search customer username', 'wc-admin' ), + remove: __( 'Remove customer username filter', 'wc-admin' ), + rule: __( 'Select a customer username filter match', 'wc-admin' ), + /* translators: A sentence describing a customer username filter. See screen shot for context: https://cloudup.com/ccxhyH2mEDg */ + title: __( 'Username {{rule /}} {{filter /}}', 'wc-admin' ), + filter: __( 'Select customer username', 'wc-admin' ), + }, + rules: [ + { + value: 'includes', + /* translators: Sentence fragment, logical, "Includes" refers to customer usernames including a given username(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Includes', 'customer usernames', 'wc-admin' ), + }, + { + value: 'excludes', + /* translators: Sentence fragment, logical, "Excludes" refers to customer usernames excluding a given username(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Excludes', 'customer usernames', 'wc-admin' ), + }, + ], + input: { + component: 'Search', + type: 'usernames', + getLabels: getRequestByIdString( NAMESPACE + 'customers', customer => ( { + id: customer.id, + label: customer.username, + } ) ), + }, + }, + order: { + labels: { + add: __( 'Order number', 'wc-admin' ), + placeholder: __( 'Search order number', 'wc-admin' ), + remove: __( 'Remove order number filter', 'wc-admin' ), + rule: __( 'Select a order number filter match', 'wc-admin' ), + /* translators: A sentence describing a order number filter. See screen shot for context: https://cloudup.com/ccxhyH2mEDg */ + title: __( 'Order number {{rule /}} {{filter /}}', 'wc-admin' ), + filter: __( 'Select order number', 'wc-admin' ), + }, + rules: [ + { + value: 'includes', + /* translators: Sentence fragment, logical, "Includes" refers to order numbers including a given order(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Includes', 'order numbers', 'wc-admin' ), + }, + { + value: 'excludes', + /* translators: Sentence fragment, logical, "Excludes" refers to order numbers excluding a given order(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Excludes', 'order numbers', 'wc-admin' ), + }, + ], + input: { + component: 'Search', + type: 'orders', + getLabels: getRequestByIdString( NAMESPACE + 'orders', order => ( { + id: order.id, + label: '#' + order.id, + } ) ), + }, + }, + downloadIp: { + labels: { + add: __( 'IP Address', 'wc-admin' ), + placeholder: __( 'Search IP address', 'wc-admin' ), + remove: __( 'Remove IP address filter', 'wc-admin' ), + rule: __( 'Select an IP address filter match', 'wc-admin' ), + /* translators: A sentence describing a order number filter. See screen shot for context: https://cloudup.com/ccxhyH2mEDg */ + title: __( 'IP Address {{rule /}} {{filter /}}', 'wc-admin' ), + filter: __( 'Select IP address', 'wc-admin' ), + }, + rules: [ + { + value: 'includes', + /* translators: Sentence fragment, logical, "Includes" refers to IP addresses including a given address(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Includes', 'IP addresses', 'wc-admin' ), + }, + { + value: 'excludes', + /* translators: Sentence fragment, logical, "Excludes" refers to IP addresses excluding a given address(s). Screenshot for context: https://cloudup.com/ccxhyH2mEDg */ + label: _x( 'Excludes', 'IP addresses', 'wc-admin' ), + }, + ], + input: { + component: 'Search', + type: 'downloadIps', + getLabels: async value => { + const ips = value.split( ',' ); + return await ips.map( ip => { + return { + id: ip, + label: ip, + }; + } ); + }, + }, + }, }, }; /*eslint-enable max-len*/ diff --git a/plugins/woocommerce-admin/client/analytics/report/products/config.js b/plugins/woocommerce-admin/client/analytics/report/products/config.js index 65db0fd36f8..311ba62f78e 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/config.js @@ -81,10 +81,10 @@ const filterConfig = { }, { label: __( 'Product Category Comparison', 'wc-admin' ), - value: 'compare-product_cats', + value: 'compare-categories', chartMode: 'item-comparison', settings: { - type: 'product_cats', + type: 'categories', param: 'categories', getLabels: getRequestByIdString( NAMESPACE + 'products/categories', category => ( { id: category.id, diff --git a/plugins/woocommerce-admin/client/analytics/report/products/style.scss b/plugins/woocommerce-admin/client/analytics/report/products/style.scss new file mode 100644 index 00000000000..d2a80f105fa --- /dev/null +++ b/plugins/woocommerce-admin/client/analytics/report/products/style.scss @@ -0,0 +1,16 @@ +/** @format */ + +.woocommerce-table__product-categories { + > .woocommerce-table__breadcrumbs { + display: inline-block; + margin-right: $gap-small; + } + .components-popover__content { + padding: 0 $gap; + text-align: left; + } + .components-popover__content .woocommerce-table__breadcrumbs { + margin-top: $gap-small; + margin-bottom: $gap-small; + } +} diff --git a/plugins/woocommerce-admin/client/analytics/report/products/table.js b/plugins/woocommerce-admin/client/analytics/report/products/table.js index 007875a96a3..9fd0a17bbbb 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/table.js @@ -2,25 +2,29 @@ /** * External dependencies */ -import { __, _n, _x } from '@wordpress/i18n'; +import { __, _n, _x, sprintf } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; +import { compose } from '@wordpress/compose'; import { map } from 'lodash'; /** * WooCommerce dependencies */ -import { Link } from '@woocommerce/components'; import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency'; import { getNewPath, getPersistedQuery } from '@woocommerce/navigation'; +import { Link, Tag } from '@woocommerce/components'; /** * Internal dependencies */ -import ReportTable from 'analytics/components/report-table'; -import { numberFormat } from 'lib/number'; +import CategoryBreacrumbs from '../categories/breadcrumbs'; import { isLowStock } from './utils'; +import { numberFormat } from 'lib/number'; +import ReportTable from 'analytics/components/report-table'; +import withSelect from 'wc-api/with-select'; +import './style.scss'; -export default class ProductsReportTable extends Component { +class ProductsReportTable extends Component { constructor() { super(); @@ -91,15 +95,20 @@ export default class ProductsReportTable extends Component { return map( data, row => { const { product_id, - sku = '', // @TODO extended_info, items_sold, net_revenue, orders_count, - categories = [], // @TODO variations = [], // @TODO } = row; - const { name, stock_status, stock_quantity, low_stock_amount } = extended_info; + const { + category_ids, + low_stock_amount, + name, + sku, + stock_status, + stock_quantity, + } = extended_info; const ordersLink = getNewPath( persistedQuery, 'orders', { filter: 'advanced', product_includes: product_id, @@ -108,6 +117,10 @@ export default class ProductsReportTable extends Component { filter: 'single_product', products: product_id, } ); + const categories = this.props.categories; + const productCategories = category_ids + .map( category_id => categories[ category_id ] ) + .filter( Boolean ); return [ { @@ -139,10 +152,29 @@ export default class ProductsReportTable extends Component { value: orders_count, }, { - display: Array.isArray( categories ) - ? categories.map( cat => cat.name ).join( ', ' ) - : '', - value: Array.isArray( categories ) ? categories.map( cat => cat.name ).join( ', ' ) : '', + display: ( +
+ { productCategories[ 0 ] && ( + + ) } + { productCategories.length > 1 && ( + ( + + ) ) } + /> + ) } +
+ ), + value: productCategories.map( category => category.name ).join( ', ' ), }, { display: numberFormat( variations.length ), @@ -219,3 +251,18 @@ export default class ProductsReportTable extends Component { ); } } + +export default compose( + withSelect( select => { + const { getCategories, getCategoriesError, isGetCategoriesRequesting } = select( 'wc-api' ); + const tableQuery = { + per_page: -1, + }; + + const categories = getCategories( tableQuery ); + const isError = Boolean( getCategoriesError( tableQuery ) ); + const isRequesting = isGetCategoriesRequesting( tableQuery ); + + return { categories, isError, isRequesting }; + } ) +)( ProductsReportTable ); diff --git a/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.js b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.js new file mode 100644 index 00000000000..8c8e56ffabc --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.js @@ -0,0 +1,51 @@ +/** @format */ +/** + * External dependencies + */ +import { Component, Fragment } from '@wordpress/element'; +import PropTypes from 'prop-types'; + +/** + * WooCommerce dependencies + */ +import { Card } from '@woocommerce/components'; + +/** + * Internal dependencies + */ +import ReportChart from 'analytics/components/report-chart'; +import './block.scss'; + +class ChartBlock extends Component { + render() { + const { charts, endpoint, path, query } = this.props; + + if ( ! charts || ! charts.length ) { + return null; + } + + return ( + + + + + + ); + } +} + +ChartBlock.propTypes = { + charts: PropTypes.array, + endpoint: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + query: PropTypes.object.isRequired, +}; + +export default ChartBlock; diff --git a/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.scss b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.scss new file mode 100644 index 00000000000..c01df312ed9 --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/block.scss @@ -0,0 +1,37 @@ +/** @format */ + +.woocommerce-dashboard__chart-block { + .woocommerce-card__body { + padding: 0; + position: relative; + + .woocommerce-chart { + border: none; + margin: 0; + + .woocommerce-legend__item > button { + cursor: default; + &:hover { + background: $core-grey-light-100; + } + .woocommerce-legend__item-container { + cursor: default; + .woocommerce-legend__item-checkmark.woocommerce-legend__item-checkmark-checked::after { + display: none; + } + } + } + + &:hover { + background: $core-grey-light-100; + .woocommerce-legend__item > button { + background: $core-grey-light-100; + } + } + } + } + + &:hover { + background: $core-grey-light-100; + } +} diff --git a/plugins/woocommerce-admin/client/dashboard/dashboard-charts/config.js b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/config.js new file mode 100644 index 00000000000..073d5bd747d --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/config.js @@ -0,0 +1,39 @@ +/** @format */ +/** + * Internal dependencies + */ + +import { charts as ordersCharts } from 'analytics/report/orders/config'; +import { charts as productsCharts } from 'analytics/report/products/config'; +import { charts as revenueCharts } from 'analytics/report/revenue/config'; +import { charts as categoriesCharts } from 'analytics/report/categories/config'; +import { charts as couponsCharts } from 'analytics/report/coupons/config'; +import { charts as taxesCharts } from 'analytics/report/taxes/config'; + +const allCharts = ordersCharts + .map( d => ( { ...d, endpoint: 'orders' } ) ) + .concat( + productsCharts.map( d => ( { ...d, endpoint: 'products' } ) ), + revenueCharts.map( d => ( { ...d, endpoint: 'revenue' } ) ), + categoriesCharts.map( d => ( { ...d, endpoint: 'categories' } ) ), + couponsCharts.map( d => ( { ...d, endpoint: 'orders' } ) ), + taxesCharts.map( d => ( { ...d, endpoint: 'taxes' } ) ) + ); + +// Need to remove duplicate charts, by key, from the configs +const uniqCharts = allCharts.reduce( ( a, b ) => { + if ( a.findIndex( d => d.key === b.key ) < 0 ) { + a.push( b ); + } + return a; +}, [] ); + +// Default charts. +// TODO: Implement user-based toggling/persistence. +const defaultCharts = [ 'items_sold', 'gross_revenue' ]; + +export const showCharts = uniqCharts.map( d => ( { + ...d, + show: defaultCharts.indexOf( d.key ) >= 0, +} ) ); +export const getChartFromKey = key => allCharts.filter( d => d.key === key ); diff --git a/plugins/woocommerce-admin/client/dashboard/dashboard-charts/index.js b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/index.js new file mode 100644 index 00000000000..56bb8dccdb2 --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/index.js @@ -0,0 +1,130 @@ +/** @format */ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import classNames from 'classnames'; +import Gridicon from 'gridicons'; +import { ToggleControl, IconButton, NavigableMenu } from '@wordpress/components'; +import { Component, Fragment } from '@wordpress/element'; +import PropTypes from 'prop-types'; + +/** + * WooCommerce dependencies + */ +import { EllipsisMenu, MenuItem, SectionHeader } from '@woocommerce/components'; + +/** + * Internal dependencies + */ +import ChartBlock from './block'; +import { getChartFromKey, showCharts } from './config'; +import './style.scss'; + +class DashboardCharts extends Component { + constructor( props ) { + super( ...arguments ); + this.state = { + showCharts, + query: props.query, + }; + + this.toggle = this.toggle.bind( this ); + } + + toggle( key ) { + return () => { + this.setState( state => { + const foundIndex = state.showCharts.findIndex( x => x.key === key ); + state.showCharts[ foundIndex ].show = ! state.showCharts[ foundIndex ].show; + return state; + } ); + }; + } + + handleTypeToggle( type ) { + return () => { + this.setState( state => ( { query: { ...state.query, type } } ) ); + }; + } + + renderMenu() { + return ( + + { this.state.showCharts.map( chart => { + return ( + + + + ); + } ) } + + ); + } + + render() { + const { path } = this.props; + const { query } = this.state; + return ( + +
+ + + } + title={ __( 'Line chart', 'wc-admin' ) } + aria-checked={ query.type === 'line' } + role="menuitemradio" + tabIndex={ query.type === 'line' ? 0 : -1 } + onClick={ this.handleTypeToggle( 'line' ) } + /> + } + title={ __( 'Bar chart', 'wc-admin' ) } + aria-checked={ query.type === 'bar' } + role="menuitemradio" + tabIndex={ query.type === 'bar' ? 0 : -1 } + onClick={ this.handleTypeToggle( 'bar' ) } + /> + + +
+ { this.state.showCharts.map( chart => { + return ! chart.show ? null : ( +
+ +
+ ); + } ) } +
+
+
+ ); + } +} + +DashboardCharts.propTypes = { + path: PropTypes.string.isRequired, + query: PropTypes.object.isRequired, +}; + +export default DashboardCharts; diff --git a/plugins/woocommerce-admin/client/dashboard/dashboard-charts/style.scss b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/style.scss new file mode 100644 index 00000000000..5ef59d5264d --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/dashboard-charts/style.scss @@ -0,0 +1,18 @@ +/** @format */ + +.woocommerce-dashboard__dashboard-charts { + border-bottom: 0; + border-right: 0; + + .woocommerce-section-header__actions { + flex-grow: 0; + } + + .woocommerce-card__body { + padding: 0; + } + + .woocommerce-summary { + margin: 0; + } +} diff --git a/plugins/woocommerce-admin/client/dashboard/index.js b/plugins/woocommerce-admin/client/dashboard/index.js index 36089e78361..dc81e1ede9e 100644 --- a/plugins/woocommerce-admin/client/dashboard/index.js +++ b/plugins/woocommerce-admin/client/dashboard/index.js @@ -12,6 +12,7 @@ import './style.scss'; import Header from 'header'; import StorePerformance from './store-performance'; import TopSellingProducts from './top-selling-products'; +import DashboardCharts from './dashboard-charts'; import { ReportFilters } from '@woocommerce/components'; export default class Dashboard extends Component { @@ -24,9 +25,10 @@ export default class Dashboard extends Component {
- +
+ ); } diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/__mocks__/top-selling-products-mock-data.js b/plugins/woocommerce-admin/client/dashboard/leaderboard/__mocks__/top-selling-products-mock-data.js similarity index 100% rename from plugins/woocommerce-admin/client/dashboard/top-selling-products/__mocks__/top-selling-products-mock-data.js rename to plugins/woocommerce-admin/client/dashboard/leaderboard/__mocks__/top-selling-products-mock-data.js diff --git a/plugins/woocommerce-admin/client/dashboard/leaderboard/index.js b/plugins/woocommerce-admin/client/dashboard/leaderboard/index.js new file mode 100644 index 00000000000..399cabc3447 --- /dev/null +++ b/plugins/woocommerce-admin/client/dashboard/leaderboard/index.js @@ -0,0 +1,96 @@ +/** @format */ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { compose } from '@wordpress/compose'; +import { get } from 'lodash'; +import PropTypes from 'prop-types'; + +/** + * WooCommerce dependencies + */ +import { Card, EmptyTable, TableCard } from '@woocommerce/components'; + +/** + * Internal dependencies + */ +import ReportError from 'analytics/components/report-error'; +import { getReportTableData } from 'store/reports/utils'; +import withSelect from 'wc-api/with-select'; +import './style.scss'; + +export class Leaderboard extends Component { + render() { + const { getHeadersContent, getRowsContent, isRequesting, isError, items, title } = this.props; + const data = get( items, [ 'data' ], [] ); + const rows = getRowsContent( data ); + + if ( isError ) { + return ; + } + + if ( ! isRequesting && rows.length === 0 ) { + return ( + + + { __( 'No data recorded for the selected time period.', 'wc-admin' ) } + + + ); + } + + return ( + + ); + } +} + +Leaderboard.propTypes = { + /** + * The endpoint to use in API calls to populate the table rows and summary. + * For example, if `taxes` is provided, data will be fetched from the report + * `taxes` endpoint (ie: `/wc/v3/reports/taxes` and `/wc/v3/reports/taxes/stats`). + * If the provided endpoint doesn't exist, an error will be shown to the user + * with `ReportError`. + */ + endpoint: PropTypes.string, + /** + * A function that returns the headers object to build the table. + */ + getHeadersContent: PropTypes.func.isRequired, + /** + * A function that returns the rows array to build the table. + */ + getRowsContent: PropTypes.func.isRequired, + /** + * Query args added to the report table endpoint request. + */ + query: PropTypes.object, + /** + * Properties to be added to the query sent to the report table endpoint. + */ + tableQuery: PropTypes.object, + /** + * String to display as the title of the table. + */ + title: PropTypes.string.isRequired, +}; + +export default compose( + withSelect( ( select, props ) => { + const { endpoint, tableQuery, query } = props; + const tableData = getReportTableData( endpoint, query, select, tableQuery ); + + return { ...tableData }; + } ) +)( Leaderboard ); diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/style.scss b/plugins/woocommerce-admin/client/dashboard/leaderboard/style.scss similarity index 86% rename from plugins/woocommerce-admin/client/dashboard/top-selling-products/style.scss rename to plugins/woocommerce-admin/client/dashboard/leaderboard/style.scss index 58719f3ece0..caa3efbebca 100644 --- a/plugins/woocommerce-admin/client/dashboard/top-selling-products/style.scss +++ b/plugins/woocommerce-admin/client/dashboard/leaderboard/style.scss @@ -1,5 +1,5 @@ /** @format */ -.woocommerce-top-selling-products { +.woocommerce-leaderboard { &.woocommerce-empty-content { margin-bottom: $gap-large; } diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js b/plugins/woocommerce-admin/client/dashboard/leaderboard/test/index.js similarity index 64% rename from plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js rename to plugins/woocommerce-admin/client/dashboard/leaderboard/test/index.js index f8ccdee55fb..2bed5593f01 100644 --- a/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js +++ b/plugins/woocommerce-admin/client/dashboard/leaderboard/test/index.js @@ -4,6 +4,7 @@ * @format */ import TestRenderer from 'react-test-renderer'; +import { map, noop } from 'lodash'; import { shallow } from 'enzyme'; import { createRegistry, RegistryProvider } from '@wordpress/data'; @@ -15,7 +16,7 @@ import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency' /** * Internal dependencies */ -import TopSellingProductsWithSelect, { TopSellingProducts } from '../'; +import LeaderboardWithSelect, { Leaderboard } from '../'; import { numberFormat } from 'lib/number'; import mockData from '../__mocks__/top-selling-products-mock-data'; @@ -26,16 +27,49 @@ jest.mock( '@woocommerce/components', () => ( { TableCard: () => null, } ) ); -describe( 'TopSellingProducts', () => { - test( 'should render empty message when there are no rows', () => { - const topSellingProducts = shallow( ); +const getRowsContent = data => { + return map( data, row => { + const { name, items_sold, net_revenue, orders_count } = row; + return [ + { + display: name, + value: name, + }, + { + display: numberFormat( items_sold ), + value: items_sold, + }, + { + display: numberFormat( orders_count ), + value: orders_count, + }, + { + display: formatCurrency( net_revenue ), + value: getCurrencyFormatDecimal( net_revenue ), + }, + ]; + } ); +}; - expect( topSellingProducts.find( 'EmptyTable' ).length ).toBe( 1 ); +describe( 'Leaderboard', () => { + test( 'should render empty message when there are no rows', () => { + const leaderboard = shallow( + + ); + + expect( leaderboard.find( 'EmptyTable' ).length ).toBe( 1 ); } ); test( 'should render correct data in the table', () => { - const topSellingProducts = shallow( ); - const table = topSellingProducts.find( 'TableCard' ); + const leaderboard = shallow( + + ); + const table = leaderboard.find( 'TableCard' ); const firstRow = table.props().rows[ 0 ]; expect( firstRow[ 0 ].value ).toBe( mockData[ 0 ].name ); @@ -47,12 +81,13 @@ describe( 'TopSellingProducts', () => { expect( firstRow[ 3 ].value ).toBe( getCurrencyFormatDecimal( mockData[ 0 ].net_revenue ) ); } ); - test( 'should load report stats from API', () => { + // TODO: Since this now uses fresh-data / wc-api, the API testing needs to be revisted. + xtest( 'should load report stats from API', () => { const getReportStatsMock = jest.fn().mockReturnValue( { data: mockData } ); const isReportStatsRequestingMock = jest.fn().mockReturnValue( false ); const isReportStatsErrorMock = jest.fn().mockReturnValue( false ); const registry = createRegistry(); - registry.registerStore( 'wc-admin', { + registry.registerStore( 'wc-api', { reducer: () => {}, selectors: { getReportStats: getReportStatsMock, @@ -60,12 +95,12 @@ describe( 'TopSellingProducts', () => { isReportStatsError: isReportStatsErrorMock, }, } ); - const topSellingProductsWrapper = TestRenderer.create( + const leaderboardWrapper = TestRenderer.create( - + ); - const topSellingProducts = topSellingProductsWrapper.root.findByType( TopSellingProducts ); + const leaderboard = leaderboardWrapper.root.findByType( Leaderboard ); const endpoint = '/wc/v3/reports/products'; const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 }; @@ -76,6 +111,6 @@ describe( 'TopSellingProducts', () => { expect( isReportStatsRequestingMock.mock.calls[ 0 ][ 2 ] ).toEqual( query ); expect( isReportStatsErrorMock.mock.calls[ 0 ][ 1 ] ).toBe( endpoint ); expect( isReportStatsErrorMock.mock.calls[ 0 ][ 2 ] ).toEqual( query ); - expect( topSellingProducts.props.data ).toBe( mockData ); + expect( leaderboard.props.data ).toBe( mockData ); } ); } ); diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js b/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js index c4904d4a5c3..5732ede5303 100644 --- a/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js +++ b/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js @@ -5,13 +5,10 @@ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { get, map } from 'lodash'; -import { compose } from '@wordpress/compose'; -import { withSelect } from '@wordpress/data'; /** * WooCommerce dependencies */ -import { Card, EmptyTable, TableCard } from '@woocommerce/components'; import { formatCurrency, getCurrencyFormatDecimal } from '@woocommerce/currency'; import { getAdminLink } from '@woocommerce/navigation'; @@ -19,11 +16,16 @@ import { getAdminLink } from '@woocommerce/navigation'; * Internal dependencies */ import { numberFormat } from 'lib/number'; -import ReportError from 'analytics/components/report-error'; -import { NAMESPACE } from 'store/constants'; -import './style.scss'; +import Leaderboard from 'dashboard/leaderboard'; export class TopSellingProducts extends Component { + constructor( props ) { + super( props ); + + this.getRowsContent = this.getRowsContent.bind( this ); + this.getHeadersContent = this.getHeadersContent.bind( this ); + } + getHeadersContent() { return [ { @@ -59,8 +61,8 @@ export class TopSellingProducts extends Component { getRowsContent( data ) { return map( data, row => { - const { product_id, items_sold, net_revenue, orders_count, name } = row; - + const { product_id, items_sold, net_revenue, orders_count, extended_info } = row; + const name = get( extended_info, [ 'name' ] ); const productLink = ( { name } ); @@ -86,53 +88,24 @@ export class TopSellingProducts extends Component { } render() { - const { data, isRequesting, isError } = this.props; - - const rows = isRequesting || isError ? [] : this.getRowsContent( data ); - const title = __( 'Top Selling Products', 'wc-admin' ); - - if ( isError ) { - return ; - } - - if ( ! isRequesting && rows.length === 0 ) { - return ( - - - { __( 'When new orders arrive, popular products will be listed here.', 'wc-admin' ) } - - - ); - } - - const headers = this.getHeadersContent(); + const tableQuery = { + orderby: 'items_sold', + order: 'desc', + per_page: 5, //TODO replace with user configured leaderboard per page value. + extended_info: true, + }; return ( - ); } } -export default compose( - withSelect( select => { - const { getReportStats, isReportStatsRequesting, isReportStatsError } = select( 'wc-admin' ); - const endpoint = NAMESPACE + 'reports/products'; - // @TODO We will need to add the date parameters from the Date Picker - // { after: '2018-04-22', before: '2018-05-06' } - const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 }; - - const stats = getReportStats( endpoint, query ); - const isRequesting = isReportStatsRequesting( endpoint, query ); - const isError = isReportStatsError( endpoint, query ); - - return { data: get( stats, 'data', [] ), isRequesting, isError }; - } ) -)( TopSellingProducts ); +export default TopSellingProducts; diff --git a/plugins/woocommerce-admin/client/header/style.scss b/plugins/woocommerce-admin/client/header/style.scss index f6150688bff..f0045cff14e 100644 --- a/plugins/woocommerce-admin/client/header/style.scss +++ b/plugins/woocommerce-admin/client/header/style.scss @@ -11,7 +11,7 @@ height: 80px; position: fixed; width: 100%; - top: 32px; + top: $adminbar-height; z-index: 99991; /* higher than component-popover (99990), lower than notification dropdown at 99999 */ &.is-scrolled { @@ -19,7 +19,7 @@ } @include breakpoint( '<782px' ) { - top: 46px; + top: $adminbar-height-mobile; height: 50px; flex-flow: row wrap; } diff --git a/plugins/woocommerce-admin/client/store/reports/items/resolvers.js b/plugins/woocommerce-admin/client/store/reports/items/resolvers.js index 13dca9b6979..811604ef1d0 100644 --- a/plugins/woocommerce-admin/client/store/reports/items/resolvers.js +++ b/plugins/woocommerce-admin/client/store/reports/items/resolvers.js @@ -14,28 +14,12 @@ import { stringifyQuery } from '@woocommerce/navigation'; /** * Internal dependencies */ -import { NAMESPACE, SWAGGERNAMESPACE } from 'store/constants'; +import { NAMESPACE } from 'store/constants'; export default { async getReportItems( ...args ) { const [ endpoint, query ] = args.slice( -2 ); - const swaggerEndpoints = [ 'coupons' ]; - if ( swaggerEndpoints.indexOf( endpoint ) >= 0 ) { - try { - const response = await fetch( - SWAGGERNAMESPACE + 'reports/' + endpoint + stringifyQuery( query ) - ); - const itemsData = await response.json(); - - dispatch( 'wc-admin' ).setReportItems( endpoint, query, itemsData ); - } catch ( error ) { - dispatch( 'wc-admin' ).setReportItemsError( endpoint, query ); - } - - return; - } - try { const response = await apiFetch( { parse: false, diff --git a/plugins/woocommerce-admin/client/store/reports/stats/resolvers.js b/plugins/woocommerce-admin/client/store/reports/stats/resolvers.js index 0cde00310d2..83f35864089 100644 --- a/plugins/woocommerce-admin/client/store/reports/stats/resolvers.js +++ b/plugins/woocommerce-admin/client/store/reports/stats/resolvers.js @@ -28,7 +28,7 @@ export default { let apiPath = endpoint + stringifyQuery( query ); // TODO: Remove once swagger endpoints are phased out. - const swaggerEndpoints = [ 'categories', 'coupons' ]; + const swaggerEndpoints = [ 'categories' ]; if ( swaggerEndpoints.indexOf( endpoint ) >= 0 ) { apiPath = SWAGGERNAMESPACE + 'reports/' + endpoint + '/stats' + stringifyQuery( query ); try { diff --git a/plugins/woocommerce-admin/client/store/reports/test/utils.js b/plugins/woocommerce-admin/client/store/reports/test/utils.js index 94c83b46ce9..90e0b604c3c 100644 --- a/plugins/woocommerce-admin/client/store/reports/test/utils.js +++ b/plugins/woocommerce-admin/client/store/reports/test/utils.js @@ -327,7 +327,7 @@ describe( 'getSummaryNumbers()', () => { } ); setGetReportStats( ( endpoint, _query ) => { - if ( '2018-10-10T00:00:00+00:00' === _query.after ) { + if ( '2018-10-10T00:00:00' === _query.after ) { return { data: { totals: totals.primary, diff --git a/plugins/woocommerce-admin/client/store/reports/utils.js b/plugins/woocommerce-admin/client/store/reports/utils.js index 233e073b5f0..a81eb662921 100644 --- a/plugins/woocommerce-admin/client/store/reports/utils.js +++ b/plugins/woocommerce-admin/client/store/reports/utils.js @@ -119,15 +119,15 @@ export function isReportDataEmpty( report ) { * @returns {Object} data request query parameters. */ function getRequestQuery( endpoint, dataType, query ) { - const datesFromQuery = getCurrentDates( query ); + const datesFromQuery = getCurrentDates( query, 'YYYY-MM-DDTHH:00:00' ); const interval = getIntervalForQuery( query ); const filterQuery = getFilterQuery( endpoint, query ); return { order: 'asc', interval, per_page: MAX_PER_PAGE, - after: appendTimestamp( datesFromQuery[ dataType ].after, 'start' ), - before: appendTimestamp( datesFromQuery[ dataType ].before, 'end' ), + after: datesFromQuery[ dataType ].after, + before: datesFromQuery[ dataType ].before, ...filterQuery, }; } diff --git a/plugins/woocommerce-admin/client/stylesheets/abstracts/_variables.scss b/plugins/woocommerce-admin/client/stylesheets/abstracts/_variables.scss index e0cce4b67ff..5a534b51442 100644 --- a/plugins/woocommerce-admin/client/stylesheets/abstracts/_variables.scss +++ b/plugins/woocommerce-admin/client/stylesheets/abstracts/_variables.scss @@ -23,3 +23,7 @@ $light-gray-500: $core-grey-light-500; $dark-gray-300: $core-grey-dark-300; $dark-gray-900: $core-grey-dark-900; $alert-red: $error-red; + +// WordPress defaults +$adminbar-height: 32px; +$adminbar-height-mobile: 46px; diff --git a/plugins/woocommerce-admin/client/stylesheets/shared/_reset.scss b/plugins/woocommerce-admin/client/stylesheets/shared/_reset.scss index abfbb60215d..8505146ce80 100644 --- a/plugins/woocommerce-admin/client/stylesheets/shared/_reset.scss +++ b/plugins/woocommerce-admin/client/stylesheets/shared/_reset.scss @@ -9,6 +9,7 @@ #wpbody-content { padding: 0; overflow-x: hidden !important; + min-height: calc(100vh - #{$adminbar-height}); } @include breakpoint( '<782px' ) { @@ -16,6 +17,10 @@ .wp-responsive-open #wpbody { right: -14.5em; } + #wpcontent, + #wpbody-content { + min-height: calc(100vh - #{$adminbar-height-mobile}); + } } @include breakpoint( '>960px' ) { diff --git a/plugins/woocommerce-admin/client/wc-api/categories/index.js b/plugins/woocommerce-admin/client/wc-api/categories/index.js new file mode 100644 index 00000000000..cd0cff2f807 --- /dev/null +++ b/plugins/woocommerce-admin/client/wc-api/categories/index.js @@ -0,0 +1,11 @@ +/** @format */ +/** + * Internal dependencies + */ +import operations from './operations'; +import selectors from './selectors'; + +export default { + operations, + selectors, +}; diff --git a/plugins/woocommerce-admin/client/wc-api/categories/operations.js b/plugins/woocommerce-admin/client/wc-api/categories/operations.js new file mode 100644 index 00000000000..6d576d6d943 --- /dev/null +++ b/plugins/woocommerce-admin/client/wc-api/categories/operations.js @@ -0,0 +1,51 @@ +/** @format */ + +/** + * External dependencies + */ +import apiFetch from '@wordpress/api-fetch'; + +/** + * WooCommerce dependencies + */ +import { stringifyQuery } from '@woocommerce/navigation'; + +/** + * Internal dependencies + */ +import { isResourcePrefix, getResourceIdentifier, getResourceName } from '../utils'; + +function read( resourceNames, fetch = apiFetch ) { + const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'category-query' ) ); + + return filteredNames.map( async resourceName => { + const query = getResourceIdentifier( resourceName ); + const url = `/wc/v3/products/categories${ stringifyQuery( query ) }`; + + try { + const categories = await fetch( { + path: url, + } ); + + const ids = categories.map( category => category.id ); + const categoryResources = categories.reduce( ( resources, category ) => { + resources[ getResourceName( 'category', category.id ) ] = { data: category }; + return resources; + }, {} ); + + return { + [ resourceName ]: { + data: ids, + totalCount: ids.length, + }, + ...categoryResources, + }; + } catch ( error ) { + return { [ resourceName ]: { error } }; + } + } ); +} + +export default { + read, +}; diff --git a/plugins/woocommerce-admin/client/wc-api/categories/selectors.js b/plugins/woocommerce-admin/client/wc-api/categories/selectors.js new file mode 100644 index 00000000000..b5d0257d7b7 --- /dev/null +++ b/plugins/woocommerce-admin/client/wc-api/categories/selectors.js @@ -0,0 +1,56 @@ +/** @format */ + +/** + * External dependencies + */ +import { isNil } from 'lodash'; + +/** + * Internal dependencies + */ +import { getResourceName } from '../utils'; +import { DEFAULT_REQUIREMENT } from '../constants'; + +const getCategories = ( getResource, requireResource ) => ( + query = {}, + requirement = DEFAULT_REQUIREMENT +) => { + const resourceName = getResourceName( 'category-query', query ); + const ids = requireResource( requirement, resourceName ).data || []; + const categories = ids.reduce( + ( acc, id ) => ( { + ...acc, + [ id ]: getResource( getResourceName( 'category', id ) ).data || {}, + } ), + {} + ); + return categories; +}; + +const getCategoriesTotalCount = getResource => ( query = {} ) => { + const resourceName = getResourceName( 'category-query', query ); + return getResource( resourceName ).totalCount || 0; +}; + +const getCategoriesError = getResource => ( query = {} ) => { + const resourceName = getResourceName( 'category-query', query ); + return getResource( resourceName ).error; +}; + +const isGetCategoriesRequesting = getResource => ( query = {} ) => { + const resourceName = getResourceName( 'category-query', query ); + const { lastRequested, lastReceived } = getResource( resourceName ); + + if ( isNil( lastRequested ) || isNil( lastReceived ) ) { + return true; + } + + return lastRequested > lastReceived; +}; + +export default { + getCategories, + getCategoriesError, + getCategoriesTotalCount, + isGetCategoriesRequesting, +}; diff --git a/plugins/woocommerce-admin/client/wc-api/reports/items/operations.js b/plugins/woocommerce-admin/client/wc-api/reports/items/operations.js index 2c21f040530..9ec07af3caa 100644 --- a/plugins/woocommerce-admin/client/wc-api/reports/items/operations.js +++ b/plugins/woocommerce-admin/client/wc-api/reports/items/operations.js @@ -17,7 +17,7 @@ import { NAMESPACE } from '../../constants'; import { SWAGGERNAMESPACE } from 'store/constants'; // TODO: Remove once swagger endpoints are phased out. -const swaggerEndpoints = [ 'coupons', 'customers', 'downloads' ]; +const swaggerEndpoints = [ 'customers', 'downloads' ]; const typeEndpointMap = { 'report-items-query-orders': 'orders', diff --git a/plugins/woocommerce-admin/client/wc-api/reports/stats/operations.js b/plugins/woocommerce-admin/client/wc-api/reports/stats/operations.js index dd3d06cc7d8..133fff60eac 100644 --- a/plugins/woocommerce-admin/client/wc-api/reports/stats/operations.js +++ b/plugins/woocommerce-admin/client/wc-api/reports/stats/operations.js @@ -16,9 +16,9 @@ import { getResourceIdentifier, getResourcePrefix } from '../../utils'; import { NAMESPACE } from '../../constants'; import { SWAGGERNAMESPACE } from 'store/constants'; -const statEndpoints = [ 'orders', 'revenue', 'products', 'taxes' ]; +const statEndpoints = [ 'orders', 'revenue', 'products', 'taxes', 'coupons' ]; // TODO: Remove once swagger endpoints are phased out. -const swaggerEndpoints = [ 'categories', 'coupons', 'downloads' ]; +const swaggerEndpoints = [ 'categories', 'downloads' ]; const typeEndpointMap = { 'report-stats-query-orders': 'orders', diff --git a/plugins/woocommerce-admin/client/wc-api/wc-api-spec.js b/plugins/woocommerce-admin/client/wc-api/wc-api-spec.js index 6bc9b887a9c..b14f3a5ef07 100644 --- a/plugins/woocommerce-admin/client/wc-api/wc-api-spec.js +++ b/plugins/woocommerce-admin/client/wc-api/wc-api-spec.js @@ -3,6 +3,7 @@ /** * Internal dependencies */ +import categories from './categories'; import customers from './customers'; import notes from './notes'; import orders from './orders'; @@ -17,6 +18,7 @@ function createWcApiSpec() { ...user.mutations, }, selectors: { + ...categories.selectors, ...customers.selectors, ...notes.selectors, ...orders.selectors, @@ -28,6 +30,7 @@ function createWcApiSpec() { operations: { read( resourceNames ) { return [ + ...categories.operations.read( resourceNames ), ...customers.operations.read( resourceNames ), ...notes.operations.read( resourceNames ), ...orders.operations.read( resourceNames ), diff --git a/plugins/woocommerce-admin/docs/components/README.md b/plugins/woocommerce-admin/docs/components/README.md index 2174cb42280..22b9c11225d 100644 --- a/plugins/woocommerce-admin/docs/components/README.md +++ b/plugins/woocommerce-admin/docs/components/README.md @@ -1,38 +1,4 @@ Components ========== -This folder contains the WooCommerce-created components. These are exported onto a global, `wc.components`, for general use. - -## How to use: - -For any files not imported into `components/index.js` (`analytics/*`, `layout/*`, `dashboard/*`, etc), we can use `import { Card, etc … } from @woocommerce/components`. - -For any `component/*` files, we should import from component-specific paths, not from `component/index.js`, to prevent circular dependencies. See `components/card/index.js` for an example. - -```jsx -import { Card, Link } from '@woocommerce/components'; - -render: function() { - return ( - - Card content with an example link. - - ); -} -``` - -## For external development - -External developers will need to enqueue the components library, `wc-components`, and then can access them from the global. - -```jsx -const { Card, Link } = wc.components; - -render: function() { - return ( - - Card content with an example link. - - ); -} -``` +This folder contains components used in `wc-admin`. They are divided in [analytics components](components/analytics), only available internally, and [package components](components/packages), which are available for plugins and third-party developers. diff --git a/plugins/woocommerce-admin/docs/components/_sidebar.md b/plugins/woocommerce-admin/docs/components/_sidebar.md index ff6f36b9cc5..e31f60031e4 100644 --- a/plugins/woocommerce-admin/docs/components/_sidebar.md +++ b/plugins/woocommerce-admin/docs/components/_sidebar.md @@ -2,30 +2,36 @@ * [Components](components/) - * [AnimationSlider](components/animation-slider.md) - * [Calendar](components/calendar.md) - * [Card](components/card.md) - * [Chart](components/chart.md) - * [Count](components/count.md) - * [DropdownButton](components/dropdown-button.md) - * [EllipsisMenu](components/ellipsis-menu.md) - * [EmptyContent](components/empty-content.md) - * [Filters](components/filters.md) - * [Flag](components/flag.md) - * [Gravatar](components/gravatar.md) - * [ImageAsset](components/image-asset.md) - * [Link](components/link.md) - * [OrderStatus](components/order-status.md) - * [Pagination](components/pagination.md) - * [ProductImage](components/product-image.md) - * [Rating](components/rating.md) - * [Search](components/search.md) - * [SectionHeader](components/section-header.md) - * [Section](components/section.md) - * [SegmentedSelection](components/segmented-selection.md) - * [SplitButton](components/split-button.md) - * [Summary](components/summary.md) - * [Table](components/table.md) - * [Tag](components/tag.md) - * [TextControlWithAffixes](components/text-control-with-affixes.md) - * [ViewMoreList](components/view-more-list.md) + * [Analytics components](components/analytics/) + * [ReportChart](components/analytics/report-chart.md) + * [ReportError](components/analytics/report-error.md) + * [ReportSummary](components/analytics/report-summary.md) + * [ReportTable](components/analytics/report-table.md) + * [Package components](components/packages/) + * [AnimationSlider](components/packages/animation-slider.md) + * [Calendar](components/packages/calendar.md) + * [Card](components/packages/card.md) + * [Chart](components/packages/chart.md) + * [Count](components/packages/count.md) + * [DropdownButton](components/packages/dropdown-button.md) + * [EllipsisMenu](components/packages/ellipsis-menu.md) + * [EmptyContent](components/packages/empty-content.md) + * [Filters](components/packages/filters.md) + * [Flag](components/packages/flag.md) + * [Gravatar](components/packages/gravatar.md) + * [ImageAsset](components/packages/image-asset.md) + * [Link](components/packages/link.md) + * [OrderStatus](components/packages/order-status.md) + * [Pagination](components/packages/pagination.md) + * [ProductImage](components/packages/product-image.md) + * [Rating](components/packages/rating.md) + * [Search](components/packages/search.md) + * [SectionHeader](components/packages/section-header.md) + * [Section](components/packages/section.md) + * [SegmentedSelection](components/packages/segmented-selection.md) + * [SplitButton](components/packages/split-button.md) + * [Summary](components/packages/summary.md) + * [Table](components/packages/table.md) + * [Tag](components/packages/tag.md) + * [TextControlWithAffixes](components/packages/text-control-with-affixes.md) + * [ViewMoreList](components/packages/view-more-list.md) \ No newline at end of file diff --git a/plugins/woocommerce-admin/docs/components/analytics/README.md b/plugins/woocommerce-admin/docs/components/analytics/README.md new file mode 100644 index 00000000000..d430bed4901 --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/analytics/README.md @@ -0,0 +1,24 @@ +Analytics Components +==================== + +This folder contains components internally used by `wc-admin`. + +## How to use: + +Analytics components can be imported by their relative or absolute path. + +```jsx +import ReportChart from 'analytics/components/report-chart'; + +render: function() { + return ( + + ); +} +``` diff --git a/plugins/woocommerce-admin/docs/components/analytics/report-chart.md b/plugins/woocommerce-admin/docs/components/analytics/report-chart.md new file mode 100644 index 00000000000..d9b113c7438 --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/analytics/report-chart.md @@ -0,0 +1,62 @@ +`ReportChart` (component) +========================= + +Component that renders the chart in reports. + +Props +----- + +### `filters` + +- Type: Array +- Default: null + +Filters available for that report. + +### `itemsLabel` + +- Type: String +- Default: null + +Label describing the legend items. + +### `path` + +- **Required** +- Type: String +- Default: null + +Current path + +### `primaryData` + +- **Required** +- Type: Object +- Default: null + +Primary data to display in the chart. + +### `query` + +- **Required** +- Type: Object +- Default: null + +The query string represented in object form. + +### `secondaryData` + +- **Required** +- Type: Object +- Default: null + +Secondary data to display in the chart. + +### `selectedChart` + +- **Required** +- Type: Object +- Default: null + +Properties of the selected chart. + diff --git a/plugins/woocommerce-admin/docs/components/analytics/report-error.md b/plugins/woocommerce-admin/docs/components/analytics/report-error.md new file mode 100644 index 00000000000..a9ba042d6ba --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/analytics/report-error.md @@ -0,0 +1,30 @@ +`ReportError` (component) +========================= + +Component to render when there is an error in a report component due to data +not being loaded or being invalid. + +Props +----- + +### `className` + +- Type: String +- Default: `''` + +Additional class name to style the component. + +### `isError` + +- Type: Boolean +- Default: null + +Boolean representing whether there was an error. + +### `isEmpty` + +- Type: Boolean +- Default: null + +Boolean representing whether the issue is that there is no data. + diff --git a/plugins/woocommerce-admin/docs/components/analytics/report-summary.md b/plugins/woocommerce-admin/docs/components/analytics/report-summary.md new file mode 100644 index 00000000000..69ac949a780 --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/analytics/report-summary.md @@ -0,0 +1,41 @@ +`ReportSummary` (component) +=========================== + +Component to render summary numbers in reports. + +Props +----- + +### `charts` + +- **Required** +- Type: Array +- Default: null + +Properties of all the charts available for that report. + +### `endpoint` + +- **Required** +- Type: String +- Default: null + +The endpoint to use in API calls. + +### `query` + +- **Required** +- Type: Object +- Default: null + +The query string represented in object form. + +### `selectedChart` + +- **Required** +- Type: Object + - key: String - Key of the selected chart. +- Default: null + +Properties of the selected chart. + diff --git a/plugins/woocommerce-admin/docs/components/analytics/report-table.md b/plugins/woocommerce-admin/docs/components/analytics/report-table.md new file mode 100644 index 00000000000..d8fd3744cff --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/analytics/report-table.md @@ -0,0 +1,96 @@ +`ReportTable` (component) +========================= + +Component that extends `TableCard` to facilitate its usage in reports. + +Props +----- + +### `columnPrefsKey` + +- Type: String +- Default: null + +The key for user preferences settings for column visibility. + +### `endpoint` + +- Type: String +- Default: null + +The endpoint to use in API calls. + +### `extendItemsMethodNames` + +- Type: Object + - getError: String + - isRequesting: String + - load: String +- Default: null + +Name of the methods available via `select( 'wc-api' )` that will be used to +load more data for table items. If omitted, no call will be made and only +the data returned by the reports endpoint will be used. + +### `getHeadersContent` + +- **Required** +- Type: Function +- Default: null + +A function that returns the headers object to build the table. + +### `getRowsContent` + +- **Required** +- Type: Function +- Default: null + +A function that returns the rows array to build the table. + +### `getSummary` + +- Type: Function +- Default: null + +A function that returns the summary object to build the table. + +### `itemIdField` + +- Type: String +- Default: null + +The name of the property in the item object which contains the id. + +### `primaryData` + +- **Required** +- Type: Object +- Default: null + +Primary data of that report. If it's not provided, it will be automatically +loaded via the provided `endpoint`. + +### `tableData` + +- Type: Object +- Default: `{}` + +Table data of that report. If it's not provided, it will be automatically +loaded via the provided `endpoint`. + +### `tableQuery` + +- Type: Object +- Default: `{}` + +Properties to be added to the query sent to the report table endpoint. + +### `title` + +- **Required** +- Type: String +- Default: null + +String to display as the title of the table. + diff --git a/plugins/woocommerce-admin/docs/components/packages/README.md b/plugins/woocommerce-admin/docs/components/packages/README.md new file mode 100644 index 00000000000..036d81e0fa3 --- /dev/null +++ b/plugins/woocommerce-admin/docs/components/packages/README.md @@ -0,0 +1,38 @@ +Package Components +================== + +This folder contains the WooCommerce-created components. These are exported onto a global, `wc.components`, for general use. + +## How to use: + +For any files not imported into `components/index.js` (`analytics/*`, `layout/*`, `dashboard/*`, etc), we can use `import { Card, etc … } from @woocommerce/components`. + +For any `component/*` files, we should import from component-specific paths, not from `component/index.js`, to prevent circular dependencies. See `components/card/index.js` for an example. + +```jsx +import { Card, Link } from '@woocommerce/components'; + +render: function() { + return ( + + Card content with an example link. + + ); +} +``` + +## For external development + +External developers will need to enqueue the components library, `wc-components`, and then can access them from the global. + +```jsx +const { Card, Link } = wc.components; + +render: function() { + return ( + + Card content with an example link. + + ); +} +``` diff --git a/plugins/woocommerce-admin/docs/components/animation-slider.md b/plugins/woocommerce-admin/docs/components/packages/animation-slider.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/animation-slider.md rename to plugins/woocommerce-admin/docs/components/packages/animation-slider.md diff --git a/plugins/woocommerce-admin/docs/components/calendar.md b/plugins/woocommerce-admin/docs/components/packages/calendar.md similarity index 62% rename from plugins/woocommerce-admin/docs/components/calendar.md rename to plugins/woocommerce-admin/docs/components/packages/calendar.md index 7140f0f13ca..95fecb2f318 100644 --- a/plugins/woocommerce-admin/docs/components/calendar.md +++ b/plugins/woocommerce-admin/docs/components/packages/calendar.md @@ -1,3 +1,56 @@ +`DatePicker` (component) +======================== + + + +Props +----- + +### `date` + +- Type: Object +- Default: null + +A moment date object representing the selected date. `null` for no selection. + +### `text` + +- Type: String +- Default: null + +The date in human-readable format. Displayed in the text input. + +### `error` + +- Type: String +- Default: null + +A string error message, shown to the user. + +### `invalidDays` + +- Type: One of type: enum, func +- Default: null + +(Coming Soon) Optionally invalidate certain days. `past`, `future`, `none`, or function are accepted. +A function will be passed to react-dates' `isOutsideRange` prop + +### `onUpdate` + +- **Required** +- Type: Function +- Default: null + +A function called upon selection of a date or input change. + +### `dateFormat` + +- **Required** +- Type: String +- Default: null + +The date format in moment.js-style tokens. + `DateRange` (component) ======================= diff --git a/plugins/woocommerce-admin/docs/components/card.md b/plugins/woocommerce-admin/docs/components/packages/card.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/card.md rename to plugins/woocommerce-admin/docs/components/packages/card.md diff --git a/plugins/woocommerce-admin/docs/components/chart.md b/plugins/woocommerce-admin/docs/components/packages/chart.md similarity index 96% rename from plugins/woocommerce-admin/docs/components/chart.md rename to plugins/woocommerce-admin/docs/components/packages/chart.md index 17a113f7be6..e1993644997 100644 --- a/plugins/woocommerce-admin/docs/components/chart.md +++ b/plugins/woocommerce-admin/docs/components/packages/chart.md @@ -20,6 +20,13 @@ An array of data. Format to parse dates into d3 time format +### `itemsLabel` + +- Type: String +- Default: null + +Label describing the legend items. + ### `path` - Type: String diff --git a/plugins/woocommerce-admin/docs/components/count.md b/plugins/woocommerce-admin/docs/components/packages/count.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/count.md rename to plugins/woocommerce-admin/docs/components/packages/count.md diff --git a/plugins/woocommerce-admin/docs/components/dropdown-button.md b/plugins/woocommerce-admin/docs/components/packages/dropdown-button.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/dropdown-button.md rename to plugins/woocommerce-admin/docs/components/packages/dropdown-button.md diff --git a/plugins/woocommerce-admin/docs/components/ellipsis-menu.md b/plugins/woocommerce-admin/docs/components/packages/ellipsis-menu.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/ellipsis-menu.md rename to plugins/woocommerce-admin/docs/components/packages/ellipsis-menu.md diff --git a/plugins/woocommerce-admin/docs/components/empty-content.md b/plugins/woocommerce-admin/docs/components/packages/empty-content.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/empty-content.md rename to plugins/woocommerce-admin/docs/components/packages/empty-content.md diff --git a/plugins/woocommerce-admin/docs/components/filters.md b/plugins/woocommerce-admin/docs/components/packages/filters.md similarity index 98% rename from plugins/woocommerce-admin/docs/components/filters.md rename to plugins/woocommerce-admin/docs/components/packages/filters.md index eb92acc7e01..6312ecbbfb3 100644 --- a/plugins/woocommerce-admin/docs/components/filters.md +++ b/plugins/woocommerce-admin/docs/components/packages/filters.md @@ -144,8 +144,8 @@ The query string represented in object form Which type of autocompleter should be used in the Search -`DatePicker` (component) -======================== +`DateRangeFilterPicker` (component) +=================================== Select a range of dates or single dates. diff --git a/plugins/woocommerce-admin/docs/components/flag.md b/plugins/woocommerce-admin/docs/components/packages/flag.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/flag.md rename to plugins/woocommerce-admin/docs/components/packages/flag.md diff --git a/plugins/woocommerce-admin/docs/components/gravatar.md b/plugins/woocommerce-admin/docs/components/packages/gravatar.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/gravatar.md rename to plugins/woocommerce-admin/docs/components/packages/gravatar.md diff --git a/plugins/woocommerce-admin/docs/components/image-asset.md b/plugins/woocommerce-admin/docs/components/packages/image-asset.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/image-asset.md rename to plugins/woocommerce-admin/docs/components/packages/image-asset.md diff --git a/plugins/woocommerce-admin/docs/components/link.md b/plugins/woocommerce-admin/docs/components/packages/link.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/link.md rename to plugins/woocommerce-admin/docs/components/packages/link.md diff --git a/plugins/woocommerce-admin/docs/components/order-status.md b/plugins/woocommerce-admin/docs/components/packages/order-status.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/order-status.md rename to plugins/woocommerce-admin/docs/components/packages/order-status.md diff --git a/plugins/woocommerce-admin/docs/components/pagination.md b/plugins/woocommerce-admin/docs/components/packages/pagination.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/pagination.md rename to plugins/woocommerce-admin/docs/components/packages/pagination.md diff --git a/plugins/woocommerce-admin/docs/components/product-image.md b/plugins/woocommerce-admin/docs/components/packages/product-image.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/product-image.md rename to plugins/woocommerce-admin/docs/components/packages/product-image.md diff --git a/plugins/woocommerce-admin/docs/components/rating.md b/plugins/woocommerce-admin/docs/components/packages/rating.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/rating.md rename to plugins/woocommerce-admin/docs/components/packages/rating.md diff --git a/plugins/woocommerce-admin/docs/components/search.md b/plugins/woocommerce-admin/docs/components/packages/search.md similarity index 86% rename from plugins/woocommerce-admin/docs/components/search.md rename to plugins/woocommerce-admin/docs/components/packages/search.md index 75e3385aafc..0408f6b2c8b 100644 --- a/plugins/woocommerce-admin/docs/components/search.md +++ b/plugins/woocommerce-admin/docs/components/packages/search.md @@ -24,7 +24,7 @@ Function called when selected results change, passed result list. ### `type` - **Required** -- Type: One of: 'products', 'product_cats', 'orders', 'customers', 'coupons', 'taxes', 'variations' +- Type: One of: 'countries', 'coupons', 'customers', 'emails', 'orders', 'products', 'product_cats', 'taxes', 'usernames', 'variations' - Default: null The object type to be used in searching. @@ -39,7 +39,7 @@ A placeholder for the search input. ### `selected` - Type: Array - - id: Number + - id: One of type: number, string - label: String - Default: `[]` diff --git a/plugins/woocommerce-admin/docs/components/section-header.md b/plugins/woocommerce-admin/docs/components/packages/section-header.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/section-header.md rename to plugins/woocommerce-admin/docs/components/packages/section-header.md diff --git a/plugins/woocommerce-admin/docs/components/section.md b/plugins/woocommerce-admin/docs/components/packages/section.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/section.md rename to plugins/woocommerce-admin/docs/components/packages/section.md diff --git a/plugins/woocommerce-admin/docs/components/segmented-selection.md b/plugins/woocommerce-admin/docs/components/packages/segmented-selection.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/segmented-selection.md rename to plugins/woocommerce-admin/docs/components/packages/segmented-selection.md diff --git a/plugins/woocommerce-admin/docs/components/split-button.md b/plugins/woocommerce-admin/docs/components/packages/split-button.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/split-button.md rename to plugins/woocommerce-admin/docs/components/packages/split-button.md diff --git a/plugins/woocommerce-admin/docs/components/summary.md b/plugins/woocommerce-admin/docs/components/packages/summary.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/summary.md rename to plugins/woocommerce-admin/docs/components/packages/summary.md diff --git a/plugins/woocommerce-admin/docs/components/table.md b/plugins/woocommerce-admin/docs/components/packages/table.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/table.md rename to plugins/woocommerce-admin/docs/components/packages/table.md diff --git a/plugins/woocommerce-admin/docs/components/tag.md b/plugins/woocommerce-admin/docs/components/packages/tag.md similarity index 95% rename from plugins/woocommerce-admin/docs/components/tag.md rename to plugins/woocommerce-admin/docs/components/packages/tag.md index f11fd5a67ab..c60cd369f5d 100644 --- a/plugins/woocommerce-admin/docs/components/tag.md +++ b/plugins/woocommerce-admin/docs/components/packages/tag.md @@ -11,7 +11,7 @@ Props ### `id` -- Type: Number +- Type: One of type: number, string - Default: null The ID for this item, used in the remove function. diff --git a/plugins/woocommerce-admin/docs/components/text-control-with-affixes.md b/plugins/woocommerce-admin/docs/components/packages/text-control-with-affixes.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/text-control-with-affixes.md rename to plugins/woocommerce-admin/docs/components/packages/text-control-with-affixes.md diff --git a/plugins/woocommerce-admin/docs/components/view-more-list.md b/plugins/woocommerce-admin/docs/components/packages/view-more-list.md similarity index 100% rename from plugins/woocommerce-admin/docs/components/view-more-list.md rename to plugins/woocommerce-admin/docs/components/packages/view-more-list.md diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php index 8bdbcad91b0..0ff064883e0 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php @@ -76,6 +76,15 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller { */ public function get_item( $request ) { $note = WC_Admin_Notes::get_note( $request->get_param( 'id' ) ); + + if ( ! $note ) { + return new WP_Error( + 'woocommerce_admin_notes_invalid_id', + __( 'Sorry, there is no resouce with that ID.', 'wc-admin' ), + array( 'status' => 404 ) + ); + } + if ( is_wp_error( $note ) ) { return $note; } diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-controller.php new file mode 100644 index 00000000000..3279885970e --- /dev/null +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-controller.php @@ -0,0 +1,40 @@ +data[] = $this->prepare_response_for_collection( + $this->prepare_item_for_response( + (object) array( + 'slug' => 'download-ips', + 'description' => __( 'An endpoint used for searching download logs for a specific IP address.', 'wc-admin' ), + ), + $request + ) + ); + return $response; + } + +} diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-download-ips-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-download-ips-controller.php new file mode 100644 index 00000000000..fcddbccd9ed --- /dev/null +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-data-download-ips-controller.php @@ -0,0 +1,167 @@ +namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Return the download IPs matching the passed parameters. + * + * @since 3.5.0 + * @param WP_REST_Request $request Request data. + * @return WP_Error|WP_REST_Response + */ + public function get_items( $request ) { + global $wpdb; + + if ( isset( $request['match'] ) ) { + $downloads = $wpdb->get_results( + $wpdb->prepare( + "SELECT DISTINCT( user_ip_address ) FROM {$wpdb->prefix}wc_download_log + WHERE user_ip_address LIKE %s + LIMIT 10", + $request['match'] . '%' + ) + ); + } else { + return new WP_Error( 'woocommerce_rest_data_download_ips_invalid_request', __( 'Invalid request. Please pass the match parameter.', 'wc-admin' ), array( 'status' => 400 ) ); + } + + $data = array(); + + if ( ! empty( $downloads ) ) { + foreach ( $downloads as $download ) { + $response = $this->prepare_item_for_response( $download, $request ); + $data[] = $this->prepare_response_for_collection( $response ); + } + } + + return rest_ensure_response( $data ); + } + + /** + * Prepare the data object for response. + * + * @since 3.5.0 + * @param object $item Data object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response $response Response data. + */ + public function prepare_item_for_response( $item, $request ) { + $data = $this->add_additional_fields_to_object( $item, $request ); + $data = $this->filter_response_by_context( $data, 'view' ); + $response = rest_ensure_response( $data ); + + $response->add_links( $this->prepare_links( $item ) ); + + /** + * Filter the ist returned from the API. + * + * @param WP_REST_Response $response The response object. + * @param array $item The original item. + * @param WP_REST_Request $request Request used to generate the response. + */ + return apply_filters( 'woocommerce_rest_prepare_data_download_ip', $response, $item, $request ); + } + + /** + * Prepare links for the request. + * + * @param object $item Data object. + * @return array Links for the given object. + */ + protected function prepare_links( $item ) { + $links = array( + 'collection' => array( + 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ), + ), + ); + return $links; + } + + /** + * Get the query params for collections. + * + * @return array + */ + public function get_collection_params() { + $params = array(); + $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); + $params['match'] = array( + 'description' => __( 'A partial IP address can be passed and matching results will be returned.', 'wc-admin' ), + 'type' => 'string', + 'validate_callback' => 'rest_validate_request_arg', + ); + return $params; + } + + + /** + * Get the schema, conforming to JSON Schema. + * + * @return array + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'data_download_ips', + 'type' => 'object', + 'properties' => array( + 'user_ip_address' => array( + 'type' => 'string', + 'description' => __( 'IP address.', 'wc-admin' ), + 'context' => array( 'view' ), + 'readonly' => true, + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } +} diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-orders-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-orders-controller.php new file mode 100644 index 00000000000..d6c28ed095a --- /dev/null +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-orders-controller.php @@ -0,0 +1,61 @@ + __( 'Limit result set to orders matching part of an order number.', 'wc-admin' ), + 'type' => 'integer', + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + ); + return $params; + } + + /** + * Prepare objects query. + * + * @param WP_REST_Request $request Full details about the request. + * @return array + */ + protected function prepare_objects_query( $request ) { + global $wpdb; + $args = parent::prepare_objects_query( $request ); + + // Search by partial order number. + if ( ! empty( $request['number'] ) ) { + $order_ids = $wpdb->get_col( + $wpdb->prepare( + "SELECT ID FROM {$wpdb->prefix}posts WHERE post_type = 'shop_order' AND ID LIKE %s", + intval( $request['number'] ) . '%' + ) + ); + + // Force WP_Query return empty if don't found any order. + $order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 ); + $args['post__in'] = $order_ids; + } + + return $args; + } +} diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-categories-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-categories-controller.php index 2b56213bff3..3aa23d33d49 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-categories-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-categories-controller.php @@ -252,9 +252,9 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro $params['orderby'] = array( 'description' => __( 'Sort collection by object attribute.', 'wc-admin' ), 'type' => 'string', - 'default' => 'date', + 'default' => 'category_id', 'enum' => array( - 'date', + 'category_id', 'items_sold', 'net_revenue', 'orders_count', diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-customers-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-customers-controller.php index b9d7821cdd4..6165b3a97f6 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-customers-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-customers-controller.php @@ -38,23 +38,26 @@ class WC_Admin_REST_Reports_Customers_Controller extends WC_REST_Reports_Control * @return array */ protected function prepare_reports_query( $request ) { - $args = array(); - $args['before'] = $request['before']; - $args['after'] = $request['after']; - $args['page'] = $request['page']; - $args['per_page'] = $request['per_page']; - $args['name'] = $request['name']; - $args['username'] = $request['username']; - $args['email'] = $request['email']; - $args['country'] = $request['country']; - $args['last_active_before'] = $request['last_active_before']; - $args['last_active_after'] = $request['last_active_after']; - $args['order_count_min'] = $request['order_count_min']; - $args['order_count_max'] = $request['order_count_max']; - $args['total_spend_min'] = $request['total_spend_min']; - $args['total_spend_max'] = $request['total_spend_max']; - $args['avg_order_value_min'] = $request['avg_order_value_min']; - $args['avg_order_value_max'] = $request['avg_order_value_max']; + $args = array(); + $args['before'] = $request['before']; + $args['after'] = $request['after']; + $args['page'] = $request['page']; + $args['per_page'] = $request['per_page']; + $args['name'] = $request['name']; + $args['username'] = $request['username']; + $args['email'] = $request['email']; + $args['country'] = $request['country']; + $args['last_active_before'] = $request['last_active_before']; + $args['last_active_after'] = $request['last_active_after']; + $args['order_count_min'] = $request['order_count_min']; + $args['order_count_max'] = $request['order_count_max']; + $args['order_count_between'] = $request['order_count_between']; + $args['total_spend_min'] = $request['total_spend_min']; + $args['total_spend_max'] = $request['total_spend_max']; + $args['total_spend_between'] = $request['total_spend_between']; + $args['avg_order_value_min'] = $request['avg_order_value_min']; + $args['avg_order_value_max'] = $request['avg_order_value_max']; + $args['avg_order_value_between'] = $request['avg_order_value_between']; return $args; } @@ -204,21 +207,21 @@ class WC_Admin_REST_Reports_Customers_Controller extends WC_REST_Reports_Control * @return array */ public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); - $params['before'] = array( + $params = array(); + $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); + $params['before'] = array( 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'wc-admin' ), 'type' => 'string', 'format' => 'date-time', 'validate_callback' => 'rest_validate_request_arg', ); - $params['after'] = array( + $params['after'] = array( 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'wc-admin' ), 'type' => 'string', 'format' => 'date-time', 'validate_callback' => 'rest_validate_request_arg', ); - $params['page'] = array( + $params['page'] = array( 'description' => __( 'Current page of the collection.', 'wc-admin' ), 'type' => 'integer', 'default' => 1, @@ -226,7 +229,7 @@ class WC_Admin_REST_Reports_Customers_Controller extends WC_REST_Reports_Control 'validate_callback' => 'rest_validate_request_arg', 'minimum' => 1, ); - $params['per_page'] = array( + $params['per_page'] = array( 'description' => __( 'Maximum number of items to be returned in result set.', 'wc-admin' ), 'type' => 'integer', 'default' => 10, @@ -235,70 +238,85 @@ class WC_Admin_REST_Reports_Customers_Controller extends WC_REST_Reports_Control 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ); - $params['name'] = array( + $params['name'] = array( 'description' => __( 'Limit response to objects with a specfic customer name.', 'wc-admin' ), 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); - $params['username'] = array( + $params['username'] = array( 'description' => __( 'Limit response to objects with a specfic username.', 'wc-admin' ), 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); - $params['email'] = array( + $params['email'] = array( 'description' => __( 'Limit response to objects equal to an email.', 'wc-admin' ), 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); - $params['country'] = array( + $params['country'] = array( 'description' => __( 'Limit response to objects with a specfic country.', 'wc-admin' ), 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); - $params['last_active_before'] = array( + $params['last_active_before'] = array( 'description' => __( 'Limit response to objects last active before (or at) a given ISO8601 compliant datetime.', 'wc-admin' ), 'type' => 'string', 'format' => 'date-time', 'validate_callback' => 'rest_validate_request_arg', ); - $params['last_active_after'] = array( + $params['last_active_after'] = array( 'description' => __( 'Limit response to objects last active after (or at) a given ISO8601 compliant datetime.', 'wc-admin' ), 'type' => 'string', 'format' => 'date-time', 'validate_callback' => 'rest_validate_request_arg', ); - $params['order_count_min'] = array( + $params['order_count_min'] = array( 'description' => __( 'Limit response to objects with an order count greater than or equal to given integer.', 'wc-admin' ), 'type' => 'integer', 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ); - $params['order_count_max'] = array( + $params['order_count_max'] = array( 'description' => __( 'Limit response to objects with an order count less than or equal to given integer.', 'wc-admin' ), 'type' => 'integer', 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ); - $params['total_spend_min'] = array( + $params['order_count_between'] = array( + 'description' => __( 'Limit response to objects with an order count between two given integers.', 'wc-admin' ), + 'type' => 'array', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['total_spend_min'] = array( 'description' => __( 'Limit response to objects with a total order spend greater than or equal to given number.', 'wc-admin' ), 'type' => 'number', 'validate_callback' => 'rest_validate_request_arg', ); - $params['total_spend_max'] = array( + $params['total_spend_max'] = array( 'description' => __( 'Limit response to objects with a total order spend less than or equal to given number.', 'wc-admin' ), 'type' => 'number', 'validate_callback' => 'rest_validate_request_arg', ); - $params['avg_order_value_min'] = array( + $params['total_spend_between'] = array( + 'description' => __( 'Limit response to objects with a total order spend between two given numbers.', 'wc-admin' ), + 'type' => 'array', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['avg_order_value_min'] = array( 'description' => __( 'Limit response to objects with an average order spend greater than or equal to given number.', 'wc-admin' ), 'type' => 'number', 'validate_callback' => 'rest_validate_request_arg', ); - $params['avg_order_value_max'] = array( + $params['avg_order_value_max'] = array( 'description' => __( 'Limit response to objects with an average order spend less than or equal to given number.', 'wc-admin' ), 'type' => 'number', 'validate_callback' => 'rest_validate_request_arg', ); + $params['avg_order_value_between'] = array( + 'description' => __( 'Limit response to objects with an average order spend between two given numbers.', 'wc-admin' ), + 'type' => 'array', + 'validate_callback' => 'rest_validate_request_arg', + ); return $params; } } diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-downloads-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-downloads-controller.php index e70a3538c30..3dc6aaf8bf9 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-downloads-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-downloads-controller.php @@ -30,4 +30,334 @@ class WC_Admin_REST_Reports_Downloads_Controller extends WC_REST_Reports_Control * @var string */ protected $rest_base = 'reports/downloads'; + + /** + * Get items. + * + * @param WP_REST_Request $request Request data. + * + * @return array|WP_Error + */ + public function get_items( $request ) { + $args = array(); + $registered = array_keys( $this->get_collection_params() ); + foreach ( $registered as $param_name ) { + if ( isset( $request[ $param_name ] ) ) { + $args[ $param_name ] = $request[ $param_name ]; + } + } + + $reports = new WC_Admin_Reports_Downloads_Query( $args ); + $downloads_data = $reports->get_data(); + + $data = array(); + + foreach ( $downloads_data->data as $download_data ) { + $item = $this->prepare_item_for_response( $download_data, $request ); + $data[] = $this->prepare_response_for_collection( $item ); + } + + $response = rest_ensure_response( $data ); + + $response->header( 'X-WP-Total', (int) $downloads_data->total ); + $response->header( 'X-WP-TotalPages', (int) $downloads_data->pages ); + + $page = $downloads_data->page_no; + $max_pages = $downloads_data->pages; + $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); + if ( $page > 1 ) { + $prev_page = $page - 1; + if ( $prev_page > $max_pages ) { + $prev_page = $max_pages; + } + $prev_link = add_query_arg( 'page', $prev_page, $base ); + $response->link_header( 'prev', $prev_link ); + } + if ( $max_pages > $page ) { + $next_page = $page + 1; + $next_link = add_query_arg( 'page', $next_page, $base ); + $response->link_header( 'next', $next_link ); + } + + return $response; + } + + /** + * Prepare a report object for serialization. + * + * @param Array $report Report data. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response + */ + public function prepare_item_for_response( $report, $request ) { + $data = $report; + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + + // Wrap the data in a response object. + $response = rest_ensure_response( $data ); + $response->add_links( $this->prepare_links( $report ) ); + + $response->data['date'] = get_date_from_gmt( $data['date_gmt'], 'Y-m-d H:i:s' ); + + // Figure out file name. + // Matches https://github.com/woocommerce/woocommerce/blob/4be0018c092e617c5d2b8c46b800eb71ece9ddef/includes/class-wc-download-handler.php#L197. + $product_id = intval( $data['product_id'] ); + $_product = wc_get_product( $product_id ); + $file_path = $_product->get_file_download_path( $data['download_id'] ); + $filename = basename( $file_path ); + $response->data['file_name'] = apply_filters( 'woocommerce_file_download_filename', $filename, $product_id ); + + /** + * Filter a report returned from the API. + * + * Allows modification of the report data right before it is returned. + * + * @param WP_REST_Response $response The response object. + * @param object $report The original report object. + * @param WP_REST_Request $request Request used to generate the response. + */ + return apply_filters( 'woocommerce_rest_prepare_report_downloads', $response, $report, $request ); + } + + /** + * Prepare links for the request. + * + * @param Array $object Object data. + * @return array Links for the given post. + */ + protected function prepare_links( $object ) { + $links = array( + 'product' => array( + 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, 'products', $object['product_id'] ) ), + 'embeddable' => true, + ), + 'user' => array( + 'href' => rest_url( 'wp/v2/users/' . $object['user_id'] ), + 'embeddable' => true, + ), + ); + + return $links; + } + + /** + * Get the Report's schema, conforming to JSON Schema. + * + * @return array + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'report_downloads', + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'type' => 'integer', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'ID.', 'wc-admin' ), + ), + 'product_id' => array( + 'type' => 'integer', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'Product ID.', 'wc-admin' ), + ), + 'date' => array( + 'description' => __( "The date of the download, in the site's timezone.", 'wc-admin' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'date_gmt' => array( + 'description' => __( 'The date of the download, as GMT.', 'wc-admin' ), + 'type' => 'date-time', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'download_id' => array( + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'Download ID.', 'wc-admin' ), + ), + 'file_name' => array( + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'File name.', 'wc-admin' ), + ), + 'product_id' => array( + 'type' => 'integer', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'Product ID.', 'wc-admin' ), + ), + 'order_id' => array( + 'type' => 'integer', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'Order ID.', 'wc-admin' ), + ), + 'user_id' => array( + 'type' => 'integer', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'User ID for the downloader.', 'wc-admin' ), + ), + 'ip_address' => array( + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'IP address for the downloader.', 'wc-admin' ), + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } + + /** + * Get the query params for collections. + * + * @return array + */ + public function get_collection_params() { + $params = array(); + $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); + $params['page'] = array( + 'description' => __( 'Current page of the collection.', 'wc-admin' ), + 'type' => 'integer', + 'default' => 1, + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + 'minimum' => 1, + ); + $params['per_page'] = array( + 'description' => __( 'Maximum number of items to be returned in result set.', 'wc-admin' ), + 'type' => 'integer', + 'default' => 10, + 'minimum' => 1, + 'maximum' => 100, + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['after'] = array( + 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'wc-admin' ), + 'type' => 'string', + 'format' => 'date-time', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['before'] = array( + 'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'wc-admin' ), + 'type' => 'string', + 'format' => 'date-time', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['order'] = array( + 'description' => __( 'Order sort attribute ascending or descending.', 'wc-admin' ), + 'type' => 'string', + 'default' => 'desc', + 'enum' => array( 'asc', 'desc' ), + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['orderby'] = array( + 'description' => __( 'Sort collection by object attribute.', 'wc-admin' ), + 'type' => 'string', + 'default' => 'date', + 'enum' => array( + 'date', + ), + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['match'] = array( + 'description' => __( 'Indicates whether all the conditions should be true for the resulting set, or if any one of them is sufficient. Match affects the following parameters: products, orders, username, ip_address.', 'wc-admin' ), + 'type' => 'string', + 'default' => 'all', + 'enum' => array( + 'all', + 'any', + ), + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['product_includes'] = array( + 'description' => __( 'Limit result set to items that have the specified product(s) assigned.', 'wc-admin' ), + 'type' => 'array', + 'items' => array( + 'type' => 'integer', + ), + 'default' => array(), + 'sanitize_callback' => 'wp_parse_id_list', + 'validate_callback' => 'rest_validate_request_arg', + + ); + $params['product_excludes'] = array( + 'description' => __( 'Limit result set to items that don\'t have the specified product(s) assigned.', 'wc-admin' ), + 'type' => 'array', + 'items' => array( + 'type' => 'integer', + ), + 'default' => array(), + 'validate_callback' => 'rest_validate_request_arg', + 'sanitize_callback' => 'wp_parse_id_list', + ); + $params['order_includes'] = array( + 'description' => __( 'Limit result set to items that have the specified order ids.', 'wc-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_id_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'integer', + ), + ); + $params['order_excludes'] = array( + 'description' => __( 'Limit result set to items that don\'t have the specified order ids.', 'wc-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_id_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'integer', + ), + ); + $params['user_includes'] = array( + 'description' => __( 'Limit response to objects that have the specified user ids.', 'wc-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_id_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'integer', + ), + ); + $params['user_excludes'] = array( + 'description' => __( 'Limit response to objects that don\'t have the specified user ids.', 'wc-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_id_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'integer', + ), + ); + $params['ip_address_includes'] = array( + 'description' => __( 'Limit response to objects that have a specified ip address.', 'wc-admin' ), + 'type' => 'array', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'string', + ), + ); + + $params['ip_address_excludes'] = array( + 'description' => __( 'Limit response to objects that don\'t have a specified ip address.', 'wc-admin' ), + 'type' => 'array', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'type' => 'string', + ), + ); + + return $params; + } } diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php index 3ae8b96bf96..4308becd3c2 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php @@ -224,6 +224,12 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll 'context' => array( 'view', 'edit' ), 'description' => __( 'Product inventory threshold for low stock.', 'wc-admin' ), ), + 'sku' => array( + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit' ), + 'description' => __( 'Product SKU.', 'wc-admin' ), + ), ), ), ); diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php index cc7b0f6b8b9..7e819d42d11 100644 --- a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php +++ b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php @@ -53,6 +53,7 @@ class WC_Admin_Api_Init { require_once dirname( __FILE__ ) . '/class-wc-admin-reports-taxes-stats-query.php'; require_once dirname( __FILE__ ) . '/class-wc-admin-reports-coupons-query.php'; require_once dirname( __FILE__ ) . '/class-wc-admin-reports-coupons-stats-query.php'; + require_once dirname( __FILE__ ) . '/class-wc-admin-reports-downloads-query.php'; // Data stores. require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-reports-data-store.php'; @@ -65,9 +66,9 @@ class WC_Admin_Api_Init { require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-reports-taxes-stats-data-store.php'; require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-reports-coupons-data-store.php'; require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-reports-coupons-stats-data-store.php'; + require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-reports-downloads-data-store.php'; // Data triggers. - require_once dirname( __FILE__ ) . '/wc-admin-order-functions.php'; require_once dirname( __FILE__ ) . '/data-stores/class-wc-admin-notes-data-store.php'; // CRUD classes. @@ -81,6 +82,9 @@ class WC_Admin_Api_Init { public function rest_api_init() { require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-admin-notes-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-customers-controller.php'; + require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-data-controller.php'; + require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-data-download-ips-controller.php'; + require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-orders-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-products-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-product-reviews-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-controller.php'; @@ -100,10 +104,14 @@ class WC_Admin_Api_Init { require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-taxes-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-taxes-stats-controller.php'; require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-stock-controller.php'; + require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-downloads-controller.php'; $controllers = array( 'WC_Admin_REST_Admin_Notes_Controller', 'WC_Admin_REST_Customers_Controller', + 'WC_Admin_REST_Data_Controller', + 'WC_Admin_REST_Data_Download_Ips_Controller', + 'WC_Admin_REST_Orders_Controller', 'WC_Admin_REST_Products_Controller', 'WC_Admin_REST_Product_Reviews_Controller', 'WC_Admin_REST_Reports_Controller', @@ -119,6 +127,7 @@ class WC_Admin_Api_Init { 'WC_Admin_REST_Reports_Coupons_Controller', 'WC_Admin_REST_Reports_Coupons_Stats_Controller', 'WC_Admin_REST_Reports_Stock_Controller', + 'WC_Admin_REST_Reports_Downloads_Controller', ); foreach ( $controllers as $controller ) { @@ -162,17 +171,6 @@ class WC_Admin_Api_Init { $endpoints['/wc/v3/reports'][0] = $endpoints['/wc/v3/reports'][1]; } - // Override /wc/v3/products. - if ( isset( $endpoints['/wc/v3/products'] ) - && isset( $endpoints['/wc/v3/products'][3] ) - && isset( $endpoints['/wc/v3/products'][2] ) - && $endpoints['/wc/v3/products'][2]['callback'][0] instanceof WC_Admin_REST_Products_Controller - && $endpoints['/wc/v3/products'][3]['callback'][0] instanceof WC_Admin_REST_Products_Controller - ) { - $endpoints['/wc/v3/products'][0] = $endpoints['/wc/v3/products'][2]; - $endpoints['/wc/v3/products'][1] = $endpoints['/wc/v3/products'][3]; - } - // Override /wc/v3/customers. if ( isset( $endpoints['/wc/v3/customers'] ) && isset( $endpoints['/wc/v3/customers'][3] ) @@ -184,6 +182,50 @@ class WC_Admin_Api_Init { $endpoints['/wc/v3/customers'][1] = $endpoints['/wc/v3/customers'][3]; } + // Override /wc/v3/orders/$id. + if ( isset( $endpoints['/wc/v3/orders/(?P[\d]+)'] ) + && isset( $endpoints['/wc/v3/orders/(?P[\d]+)'][5] ) + && isset( $endpoints['/wc/v3/orders/(?P[\d]+)'][4] ) + && isset( $endpoints['/wc/v3/orders/(?P[\d]+)'][3] ) + && $endpoints['/wc/v3/orders/(?P[\d]+)'][3]['callback'][0] instanceof WC_Admin_REST_Orders_Controller + && $endpoints['/wc/v3/orders/(?P[\d]+)'][4]['callback'][0] instanceof WC_Admin_REST_Orders_Controller + && $endpoints['/wc/v3/orders/(?P[\d]+)'][5]['callback'][0] instanceof WC_Admin_REST_Orders_Controller + ) { + $endpoints['/wc/v3/orders/(?P[\d]+)'][0] = $endpoints['/wc/v3/orders/(?P[\d]+)'][3]; + $endpoints['/wc/v3/orders/(?P[\d]+)'][1] = $endpoints['/wc/v3/orders/(?P[\d]+)'][4]; + $endpoints['/wc/v3/orders/(?P[\d]+)'][2] = $endpoints['/wc/v3/orders/(?P[\d]+)'][5]; + } + + // Override /wc/v3orders. + if ( isset( $endpoints['/wc/v3/orders'] ) + && isset( $endpoints['/wc/v3/orders'][3] ) + && isset( $endpoints['/wc/v3/orders'][2] ) + && $endpoints['/wc/v3/orders'][2]['callback'][0] instanceof WC_Admin_REST_Orders_Controller + && $endpoints['/wc/v3/orders'][3]['callback'][0] instanceof WC_Admin_REST_Orders_Controller + ) { + $endpoints['/wc/v3/orders'][0] = $endpoints['/wc/v3/orders'][2]; + $endpoints['/wc/v3/orders'][1] = $endpoints['/wc/v3/orders'][3]; + } + + // Override /wc/v3/data. + if ( isset( $endpoints['/wc/v3/data'] ) + && isset( $endpoints['/wc/v3/data'][1] ) + && $endpoints['/wc/v3/data'][1]['callback'][0] instanceof WC_Admin_REST_Data_Controller + ) { + $endpoints['/wc/v3/data'][0] = $endpoints['/wc/v3/data'][1]; + } + + // Override /wc/v3/products. + if ( isset( $endpoints['/wc/v3/products'] ) + && isset( $endpoints['/wc/v3/products'][3] ) + && isset( $endpoints['/wc/v3/products'][2] ) + && $endpoints['/wc/v3/products'][2]['callback'][0] instanceof WC_Admin_REST_Products_Controller + && $endpoints['/wc/v3/products'][3]['callback'][0] instanceof WC_Admin_REST_Products_Controller + ) { + $endpoints['/wc/v3/products'][0] = $endpoints['/wc/v3/products'][2]; + $endpoints['/wc/v3/products'][1] = $endpoints['/wc/v3/products'][3]; + } + // Override /wc/v3/products/$id. if ( isset( $endpoints['/wc/v3/products/(?P[\d]+)'] ) && isset( $endpoints['/wc/v3/products/(?P[\d]+)'][5] ) @@ -215,7 +257,7 @@ class WC_Admin_Api_Init { /** * Regenerate data for reports. */ - public static function regenrate_report_data() { + public static function regenerate_report_data() { WC_Admin_Reports_Orders_Data_Store::queue_order_stats_repopulate_database(); self::order_product_lookup_store_init(); } @@ -234,7 +276,7 @@ class WC_Admin_Api_Init { 'name' => __( 'Rebuild reports data', 'wc-admin' ), 'button' => __( 'Rebuild reports', 'wc-admin' ), 'desc' => __( 'This tool will rebuild all of the information used by the reports.', 'wc-admin' ), - 'callback' => array( 'WC_Admin_Api_Init', 'regenrate_report_data' ), + 'callback' => array( 'WC_Admin_Api_Init', 'regenerate_report_data' ), ), ) ); @@ -245,6 +287,9 @@ class WC_Admin_Api_Init { */ public static function orders_data_store_init() { WC_Admin_Reports_Orders_Data_Store::init(); + WC_Admin_Reports_Products_Data_Store::init(); + WC_Admin_Reports_Taxes_Data_Store::init(); + WC_Admin_Reports_Coupons_Data_Store::init(); } /** @@ -270,35 +315,7 @@ class WC_Admin_Api_Init { // Process orders until close to running out of memory timeouts on large sites then requeue. foreach ( $orders as $order_id ) { - $order = wc_get_order( $order_id ); - if ( ! $order ) { - continue; - } - foreach ( $order->get_items() as $order_item ) { - $wpdb->replace( - $wpdb->prefix . 'wc_order_product_lookup', - array( - 'order_item_id' => $order_item->get_id(), - 'order_id' => $order->get_id(), - 'product_id' => $order_item->get_product_id( 'edit' ), - 'variation_id' => $order_item->get_variation_id( 'edit' ), - 'customer_id' => ( 0 < $order->get_customer_id( 'edit' ) ) ? $order->get_customer_id( 'edit' ) : null, - 'product_qty' => $order_item->get_quantity( 'edit' ), - 'product_net_revenue' => $order_item->get_subtotal( 'edit' ), - 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), - ), - array( - '%d', - '%d', - '%d', - '%d', - '%d', - '%d', - '%f', - '%s', - ) - ); - } + WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ); // Pop the order ID from the array for updating the transient later should we near memory exhaustion. unset( $orders[ $order_id ] ); if ( $updater instanceof WC_Background_Updater && $updater->is_memory_exceeded() ) { @@ -331,6 +348,7 @@ class WC_Admin_Api_Init { 'report-taxes-stats' => 'WC_Admin_Reports_Taxes_Stats_Data_Store', 'report-coupons' => 'WC_Admin_Reports_Coupons_Data_Store', 'report-coupons-stats' => 'WC_Admin_Reports_Coupons_Stats_Data_Store', + 'report-downloads' => 'WC_Admin_Reports_Downloads_Data_Store', 'admin-note' => 'WC_Admin_Notes_Data_Store', ) ); @@ -477,6 +495,17 @@ class WC_Admin_Api_Init { add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'order_product_lookup_store_init' ), 20 ); } + /** + * Enables the WP REST API for product categories + * + * @param array $args Default arguments for product_cat taxonomy. + * @return array + */ + public static function show_product_categories_in_rest( $args ) { + $args['show_in_rest'] = true; + return $args; + } + } new WC_Admin_Api_Init(); diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-reports-downloads-query.php b/plugins/woocommerce-admin/includes/class-wc-admin-reports-downloads-query.php new file mode 100644 index 00000000000..aaeaa25c3c0 --- /dev/null +++ b/plugins/woocommerce-admin/includes/class-wc-admin-reports-downloads-query.php @@ -0,0 +1,47 @@ + '2018-07-19 00:00:00', + * 'after' => '2018-07-05 00:00:00', + * 'page' => 2, + * 'products' => array(1,2,3) + * ); + * $report = new WC_Admin_Reports_Downloads_Query( $args ); + * $mydata = $report->get_data(); + * + * @package WooCommerce Admin/Classes + */ + +defined( 'ABSPATH' ) || exit; + +/** + * WC_Admin_Reports_Downloads_Query + */ +class WC_Admin_Reports_Downloads_Query extends WC_Admin_Reports_Query { + + /** + * Valid fields for downloads report. + * + * @return array + */ + protected function get_default_query_vars() { + return array(); + } + + /** + * Get downloads data based on the current query vars. + * + * @return array + */ + public function get_data() { + $args = apply_filters( 'woocommerce_reports_downloads_query_args', $this->get_query_vars() ); + + $data_store = WC_Data_Store::load( 'report-downloads' ); + $results = $data_store->get_data( $args ); + return apply_filters( 'woocommerce_reports_downloads_select_query', $results, $args ); + } + +} diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php index 85a8db789a4..9cee07babe8 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php @@ -53,10 +53,10 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store * @var array */ protected $report_columns = array( - 'items_sold' => 'SUM(product_qty) as items_sold', - 'net_revenue' => 'SUM(product_net_revenue) AS net_revenue', - 'orders_count' => 'COUNT(DISTINCT order_id) as orders_count', - // 'products_count' is not a SQL column at the moment, see below. + 'items_sold' => 'SUM(product_qty) as items_sold', + 'net_revenue' => 'SUM(product_net_revenue) AS net_revenue', + 'orders_count' => 'COUNT(DISTINCT order_id) as orders_count', + 'products_count' => 'COUNT(DISTINCT product_id) as products_count', ); /** @@ -73,6 +73,16 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store // Limit is left out here so that the grouping in code by PHP can be applied correctly. $sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) ); + // join wp_order_product_lookup_table with relationships and taxonomies + // @TODO: How to handle custom product tables? + $sql_query_params['from_clause'] .= " LEFT JOIN {$wpdb->prefix}term_relationships ON {$order_product_lookup_table}.product_id = {$wpdb->prefix}term_relationships.object_id"; + $sql_query_params['from_clause'] .= " LEFT JOIN {$wpdb->prefix}term_taxonomy ON {$wpdb->prefix}term_relationships.term_taxonomy_id = {$wpdb->prefix}term_taxonomy.term_taxonomy_id"; + + $included_categories = $this->get_included_categories( $query_args ); + if ( $included_categories ) { + $sql_query_params['where_clause'] .= " AND {$wpdb->prefix}term_taxonomy.term_id IN ({$included_categories})"; + } + // TODO: only products in the category C or orders with products from category C (and, possibly others?). $included_products = $this->get_included_products( $query_args ); if ( $included_products ) { @@ -85,21 +95,24 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store $sql_query_params['where_clause'] .= " AND ( {$order_status_filter} )"; } + $sql_query_params['where_clause'] .= " AND taxonomy = 'product_cat' "; + return $sql_query_params; } /** - * Maps ordering specified by the user to columns in the database/fields in the data. + * Returns comma separated ids of included categories, based on query arguments from the user. * - * @param string $order_by Sorting criterion. + * @param array $query_args Parameters supplied by the user. * @return string */ - protected function normalize_order_by( $order_by ) { - if ( 'date' === $order_by ) { - return 'date_created'; - } + protected function get_included_categories( $query_args ) { + $included_categories_str = ''; - return $order_by; + if ( isset( $query_args['categories'] ) && is_array( $query_args['categories'] ) && count( $query_args['categories'] ) > 0 ) { + $included_categories_str = implode( ',', $query_args['categories'] ); + } + return $included_categories_str; } /** @@ -208,10 +221,9 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store $selections = $this->selected_columns( $query_args ); $sql_query_params = $this->get_sql_query_params( $query_args ); - $products_data = $wpdb->get_results( + $categories_data = $wpdb->get_results( "SELECT - product_id, - date_created, + term_id as category_id, {$selections} FROM {$table_name} @@ -221,39 +233,15 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store {$sql_query_params['where_time_clause']} {$sql_query_params['where_clause']} GROUP BY - product_id + category_id ", ARRAY_A ); // WPCS: cache ok, DB call ok, unprepared SQL ok. - if ( null === $products_data ) { + if ( null === $categories_data ) { return new WP_Error( 'woocommerce_reports_categories_result_failed', __( 'Sorry, fetching revenue data failed.', 'wc-admin' ), array( 'status' => 500 ) ); } - // Group by category without a helper table, worst case we add it and change the SQL afterwards. - // Other option would be a join with wp_post and taxonomies, but a) performance might be bad, b) how to handle custom product tables? - $categories_data = array(); - foreach ( $products_data as $product_data ) { - $categories = get_the_terms( $product_data['product_id'], 'product_cat' ); - foreach ( $categories as $category ) { - $cat_id = $category->term_id; - if ( ! key_exists( $cat_id, $categories_data ) ) { - $categories_data[ $cat_id ] = array( - 'category_id' => 0, - 'items_sold' => 0, - 'net_revenue' => 0.0, - 'orders_count' => 0, - 'products_count' => 0, - ); - } - - $categories_data[ $cat_id ]['category_id'] = $cat_id; - $categories_data[ $cat_id ]['items_sold'] += $product_data['items_sold']; - $categories_data[ $cat_id ]['net_revenue'] += $product_data['net_revenue']; - $categories_data[ $cat_id ]['orders_count'] += $product_data['orders_count']; - $categories_data[ $cat_id ]['products_count'] ++; - } - } $record_count = count( $categories_data ); $total_pages = (int) ceil( $record_count / $query_args['per_page'] ); if ( $query_args['page'] < 1 || $query_args['page'] > $total_pages ) { diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php index 779e116c325..95111752886 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php @@ -41,6 +41,15 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im 'orders_count' => 'COUNT(DISTINCT order_id) as orders_count', ); + /** + * Set up all the hooks for maintaining and populating table data. + */ + public static function init() { + add_action( 'save_post', array( __CLASS__, 'sync_order_coupons' ) ); + add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_coupons' ) ); + add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_coupons' ) ); + } + /** * Returns comma separated ids of included coupons, based on query arguments from the user. * @@ -249,4 +258,48 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im return 'woocommerce_' . self::TABLE_NAME . '_' . md5( wp_json_encode( $params ) ); } + /** + * Create or update an an entry in the wc_order_coupon_lookup table for an order. + * + * @since 3.5.0 + * @param int $order_id Order ID. + * @return void + */ + public static function sync_order_coupons( $order_id ) { + global $wpdb; + + $order = wc_get_order( $order_id ); + if ( ! $order ) { + return; + } + + if ( ! in_array( $order->get_status(), parent::get_report_order_statuses(), true ) ) { + $wpdb->delete( + $wpdb->prefix . self::TABLE_NAME, + array( 'order_id' => $order->get_id() ), + array( '%d' ) + ); + return; + } + + $coupon_items = $order->get_items( 'coupon' ); + foreach ( $coupon_items as $coupon_item ) { + $wpdb->replace( + $wpdb->prefix . self::TABLE_NAME, + array( + 'order_id' => $order_id, + 'coupon_id' => wc_get_coupon_id_by_code( $coupon_item->get_code() ), + 'discount_amount' => $coupon_item->get_discount(), + 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), + ), + array( + '%d', + '%d', + '%f', + '%s', + ) + ); + } + } + } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php index 7060882f342..83b16a19740 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php @@ -635,6 +635,65 @@ class WC_Admin_Reports_Data_Store { return $excluded_coupons_str; } + /** + * Returns comma separated ids of included orders, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_included_orders( $query_args ) { + $included_orders_str = ''; + + if ( isset( $query_args['order_includes'] ) && is_array( $query_args['order_includes'] ) && count( $query_args['order_includes'] ) > 0 ) { + $included_orders_str = implode( ',', $query_args['order_includes'] ); + } + return $included_orders_str; + } + + /** + * Returns comma separated ids of excluded orders, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_excluded_orders( $query_args ) { + $excluded_orders_str = ''; + + if ( isset( $query_args['order_excludes'] ) && is_array( $query_args['order_excludes'] ) && count( $query_args['order_excludes'] ) > 0 ) { + $excluded_orders_str = implode( ',', $query_args['order_excludes'] ); + } + return $excluded_orders_str; + } + + /** + * Returns comma separated ids of included users, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_included_users( $query_args ) { + $included_users_str = ''; + + if ( isset( $query_args['user_includes'] ) && is_array( $query_args['user_includes'] ) && count( $query_args['user_includes'] ) > 0 ) { + $included_users_str = implode( ',', $query_args['user_includes'] ); + } + return $included_users_str; + } + + /** + * Returns comma separated ids of excluded users, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_excluded_users( $query_args ) { + $excluded_users_str = ''; + + if ( isset( $query_args['user_excludes'] ) && is_array( $query_args['user_excludes'] ) && count( $query_args['user_excludes'] ) > 0 ) { + $excluded_users_str = implode( ',', $query_args['user_excludes'] ); + } + return $excluded_users_str; + } /** * Returns order status subquery to be used in WHERE SQL query, based on query arguments from the user. diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-downloads-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-downloads-data-store.php new file mode 100644 index 00000000000..86555a8b1ec --- /dev/null +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-downloads-data-store.php @@ -0,0 +1,383 @@ + 'intval', + 'date' => 'strval', + 'date_gmt' => 'strval', + 'download_id' => 'strval', // String because this can sometimes be a hash. + 'file_name' => 'strval', + 'product_id' => 'intval', + 'order_id' => 'intval', + 'user_id' => 'intval', + 'ip_address' => 'strval', + ); + + /** + * SQL columns to select in the db query and their mapping to SQL code. + * + * @var array + */ + protected $report_columns = array( + 'id' => 'download_log_id as id', + 'date' => 'timestamp as date_gmt', + 'download_id' => 'product_permissions.download_id', + 'product_id' => 'product_permissions.product_id', + 'order_id' => 'product_permissions.order_id', + 'user_id' => 'product_permissions.user_id', + 'ip_address' => 'user_ip_address as ip_address', + ); + + /** + * Constructor + */ + public function __construct() { + global $wpdb; + } + + /** + * Updates the database query with parameters used for downloads report. + * + * @param array $query_args Query arguments supplied by the user. + * @return array Array of parameters used for SQL query. + */ + protected function get_sql_query_params( $query_args ) { + global $wpdb; + + $lookup_table = $wpdb->prefix . self::TABLE_NAME; + $operator = $this->get_match_operator( $query_args ); + $where_filters = array(); + + $sql_query_params = $this->get_time_period_sql_params( $query_args, $lookup_table ); + $sql_query_params = array_merge( $sql_query_params, $this->get_limit_sql_params( $query_args ) ); + $sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) ); + + $included_products = $this->get_included_products( $query_args ); + $excluded_products = $this->get_excluded_products( $query_args ); + if ( $included_products ) { + $where_filters[] = " {$lookup_table}.permission_id IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.product_id IN ({$included_products}) + )"; + } + + if ( $excluded_products ) { + $where_filters[] = " {$lookup_table}.permission_id NOT IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.product_id IN ({$excluded_products}) + )"; + } + + $included_orders = $this->get_included_orders( $query_args ); + $excluded_orders = $this->get_excluded_orders( $query_args ); + if ( $included_orders ) { + $where_filters[] = " {$lookup_table}.permission_id IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.order_id IN ({$included_orders}) + )"; + } + + if ( $excluded_orders ) { + $where_filters[] = " {$lookup_table}.permission_id NOT IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.order_id IN ({$excluded_orders}) + )"; + } + + $included_users = $this->get_included_users( $query_args ); + $excluded_users = $this->get_excluded_users( $query_args ); + if ( $included_users ) { + $where_filters[] = " {$lookup_table}.permission_id IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN ({$included_users}) + )"; + } + + if ( $excluded_users ) { + $where_filters[] = " {$lookup_table}.permission_id NOT IN ( + SELECT + DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id + FROM + {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE + {$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN ({$excluded_users}) + )"; + } + + $included_ip_addresses = $this->get_included_ip_addresses( $query_args ); + $excluded_ip_addresses = $this->get_excluded_ip_addresses( $query_args ); + if ( $included_ip_addresses ) { + $where_filters[] = " {$lookup_table}.user_ip_address IN ('{$included_ip_addresses}')"; + } + + if ( $excluded_ip_addresses ) { + $where_filters[] = " {$lookup_table}.user_ip_address NOT IN ('{$excluded_ip_addresses}')"; + } + + $where_subclause = implode( " $operator ", $where_filters ); + if ( $where_subclause ) { + $sql_query_params['where_clause'] .= " AND ( $where_subclause )"; + } + + $sql_query_params['from_clause'] .= " JOIN {$wpdb->prefix}woocommerce_downloadable_product_permissions as product_permissions ON {$lookup_table}.permission_id = product_permissions.permission_id"; + + return $sql_query_params; + } + + /** + * Returns comma separated ids of included ip address, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_included_ip_addresses( $query_args ) { + $included_ips_str = ''; + + if ( isset( $query_args['ip_address_includes'] ) && is_array( $query_args['ip_address_includes'] ) && count( $query_args['ip_address_includes'] ) > 0 ) { + $ip_includes = array(); + foreach ( $query_args['ip_address_includes'] as $ip ) { + $ip_includes[] = esc_sql( $ip ); + } + $included_ips_str = implode( "','", $ip_includes ); + } + return $included_ips_str; + } + + /** + * Returns comma separated ids of excluded ip address, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_excluded_ip_addresses( $query_args ) { + $excluded_ips_str = ''; + + if ( isset( $query_args['ip_address_excludes'] ) && is_array( $query_args['ip_address_excludes'] ) && count( $query_args['ip_address_excludes'] ) > 0 ) { + $ip_excludes = array(); + foreach ( $query_args['ip_address_excludes'] as $ip ) { + $ip_excludes[] = esc_sql( $ip ); + } + $excluded_ips_str = implode( ',', $ip_excludes ); + } + return $excluded_ips_str; + } + + + /** + * Fills WHERE clause of SQL request with date-related constraints. + * + * @param array $query_args Parameters supplied by the user. + * @param string $table_name Name of the db table relevant for the date constraint. + * @return array + */ + protected function get_time_period_sql_params( $query_args, $table_name ) { + $sql_query = array( + 'from_clause' => '', + 'where_time_clause' => '', + 'where_clause' => '', + ); + + if ( isset( $query_args['before'] ) && '' !== $query_args['before'] ) { + $datetime = new DateTime( $query_args['before'] ); + $datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format ); + $sql_query['where_time_clause'] .= " AND {$table_name}.timestamp <= '$datetime_str'"; + + } + + if ( isset( $query_args['after'] ) && '' !== $query_args['after'] ) { + $datetime = new DateTime( $query_args['after'] ); + $datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format ); + $sql_query['where_time_clause'] .= " AND {$table_name}.timestamp >= '$datetime_str'"; + } + + return $sql_query; + } + + /** + * Fills ORDER BY clause of SQL request based on user supplied parameters. + * + * @param array $query_args Parameters supplied by the user. + * @return array + */ + protected function get_order_by_sql_params( $query_args ) { + $sql_query['order_by_clause'] = ''; + if ( isset( $query_args['orderby'] ) ) { + $sql_query['order_by_clause'] = $this->normalize_order_by( $query_args['orderby'] ); + } + + if ( isset( $query_args['order'] ) ) { + $sql_query['order_by_clause'] .= ' ' . $query_args['order']; + } else { + $sql_query['order_by_clause'] .= ' DESC'; + } + + return $sql_query; + } + + /** + * Returns the report data based on parameters supplied by the user. + * + * @param array $query_args Query parameters. + * @return stdClass|WP_Error Data. + */ + public function get_data( $query_args ) { + global $wpdb; + + $table_name = $wpdb->prefix . self::TABLE_NAME; + $now = time(); + $week_back = $now - WEEK_IN_SECONDS; + + // These defaults are only partially applied when used via REST API, as that has its own defaults. + $defaults = array( + 'per_page' => get_option( 'posts_per_page' ), + 'page' => 1, + 'order' => 'DESC', + 'orderby' => 'timestamp', + 'before' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $now ), + 'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ), + 'fields' => '*', + ); + $query_args = wp_parse_args( $query_args, $defaults ); + + $cache_key = $this->get_cache_key( $query_args ); + $data = wp_cache_get( $cache_key, $this->cache_group ); + + if ( false === $data ) { + $data = (object) array( + 'data' => array(), + 'total' => 0, + 'pages' => 0, + 'page_no' => 0, + ); + + $selections = $this->selected_columns( $query_args ); + $sql_query_params = $this->get_sql_query_params( $query_args ); + + $db_records_count = (int) $wpdb->get_var( + "SELECT COUNT(*) FROM ( + SELECT + {$table_name}.download_log_id + FROM + {$table_name} + {$sql_query_params['from_clause']} + WHERE + 1=1 + {$sql_query_params['where_time_clause']} + {$sql_query_params['where_clause']} + GROUP BY + {$table_name}.download_log_id + ) AS tt" + ); // WPCS: cache ok, DB call ok, unprepared SQL ok. + + $total_pages = (int) ceil( $db_records_count / $sql_query_params['per_page'] ); + if ( $query_args['page'] < 1 || $query_args['page'] > $total_pages ) { + return $data; + } + + $download_data = $wpdb->get_results( + "SELECT + {$selections} + FROM + {$table_name} + {$sql_query_params['from_clause']} + WHERE + 1=1 + {$sql_query_params['where_time_clause']} + {$sql_query_params['where_clause']} + GROUP BY + {$table_name}.download_log_id + ORDER BY + {$sql_query_params['order_by_clause']} + {$sql_query_params['limit']} + ", + ARRAY_A + ); // WPCS: cache ok, DB call ok, unprepared SQL ok. + + if ( null === $download_data ) { + return $data; + } + + $download_data = array_map( array( $this, 'cast_numbers' ), $download_data ); + $data = (object) array( + 'data' => $download_data, + 'total' => $db_records_count, + 'pages' => $total_pages, + 'page_no' => (int) $query_args['page'], + ); + + wp_cache_set( $cache_key, $data, $this->cache_group ); + } + + return $data; + } + + /** + * Returns string to be used as cache key for the data. + * + * @param array $params Query parameters. + * @return string + */ + protected function get_cache_key( $params ) { + return 'woocommerce_' . self::TABLE_NAME . '_' . md5( wp_json_encode( $params ) ); + } + + /** + * Maps ordering specified by the user to columns in the database/fields in the data. + * + * @param string $order_by Sorting criterion. + * @return string + */ + protected function normalize_order_by( $order_by ) { + global $wpdb; + + if ( 'date' === $order_by ) { + return $wpdb->prefix . 'wc_download_log.timestamp'; + } + + return $order_by; + } + +} diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-data-store.php index 0bb64666677..0e0e3ae0add 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-data-store.php @@ -66,7 +66,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp 'shipping' => 'SUM(shipping_total) AS shipping', 'net_revenue' => '( SUM(net_total) - SUM(refund_total) ) AS net_revenue', 'avg_items_per_order' => 'AVG(num_items_sold) AS avg_items_per_order', - 'avg_order_value' => 'AVG(gross_total) AS avg_order_value', + 'avg_order_value' => '( SUM(net_total) - SUM(refund_total) ) / COUNT(*) AS avg_order_value', 'num_returning_customers' => 'SUM(returning_customer = 1) AS num_returning_customers', 'num_new_customers' => 'SUM(returning_customer = 0) AS num_new_customers', ); @@ -95,6 +95,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp // TODO: this is required as order update skips save_post. add_action( 'clean_post_cache', array( __CLASS__, 'sync_order' ) ); add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order' ) ); + add_action( 'woocommerce_refund_deleted', array( __CLASS__, 'sync_on_refund_delete' ), 10, 2 ); if ( ! self::$background_process ) { self::$background_process = new WC_Admin_Order_Stats_Background_Process(); @@ -711,6 +712,16 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp self::update( $order ); } + /** + * Syncs order information when a refund is deleted. + * + * @param int $refund_id Refund ID. + * @param int $order_id Order ID. + */ + public static function sync_on_refund_delete( $refund_id, $order_id ) { + self::sync_order( $order_id ); + } + /** * Update the database with stats data. * diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php index 32ef3da268b..df0a74211b3 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php @@ -25,17 +25,22 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i * @var array */ protected $column_types = array( - 'date_start' => 'strval', - 'date_end' => 'strval', - 'product_id' => 'intval', - 'items_sold' => 'intval', - 'net_revenue' => 'floatval', - 'orders_count' => 'intval', + 'date_start' => 'strval', + 'date_end' => 'strval', + 'product_id' => 'intval', + 'items_sold' => 'intval', + 'net_revenue' => 'floatval', + 'orders_count' => 'intval', // Extended attributes. - 'name' => 'strval', - 'price' => 'floatval', - 'image' => 'strval', - 'permalink' => 'strval', + 'name' => 'strval', + 'price' => 'floatval', + 'image' => 'strval', + 'permalink' => 'strval', + 'stock_status' => 'strval', + 'stock_quantity' => 'intval', + 'low_stock_amount' => 'intval', + 'category_ids' => 'array_values', + 'sku' => 'strval', ); /** @@ -63,8 +68,19 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i 'stock_status', 'stock_quantity', 'low_stock_amount', + 'category_ids', + 'sku', ); + /** + * Set up all the hooks for maintaining and populating table data. + */ + public static function init() { + add_action( 'save_post', array( __CLASS__, 'sync_order_products' ) ); + add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_products' ) ); + add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_products' ) ); + } + /** * Fills ORDER BY clause of SQL request based on user supplied parameters. * @@ -282,4 +298,93 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i return 'woocommerce_' . self::TABLE_NAME . '_' . md5( wp_json_encode( $params ) ); } + /** + * Create or update an entry in the wc_admin_order_product_lookup table for an order. + * + * @since 3.5.0 + * @param int $order_id Order ID. + * @return void + */ + public static function sync_order_products( $order_id ) { + global $wpdb; + + $order = wc_get_order( $order_id ); + + // This hook gets called on refunds as well, so return early to avoid errors. + if ( ! $order || 'shop_order_refund' === $order->get_type() ) { + return; + } + + if ( ! in_array( $order->get_status(), parent::get_report_order_statuses(), true ) ) { + $wpdb->delete( + $wpdb->prefix . self::TABLE_NAME, + array( 'order_id' => $order->get_id() ), + array( '%d' ) + ); + return; + } + + $refunds = self::get_order_refund_items( $order ); + + foreach ( $order->get_items() as $order_item ) { + $order_item_id = $order_item->get_id(); + $quantity_refunded = isset( $refunds[ $order_item_id ] ) ? $refunds[ $order_item_id ]['quantity'] : 0; + $amount_refunded = isset( $refunds[ $order_item_id ] ) ? $refunds[ $order_item_id ]['subtotal'] : 0; + if ( $quantity_refunded >= $order_item->get_quantity( 'edit' ) ) { + $wpdb->delete( + $wpdb->prefix . self::TABLE_NAME, + array( 'order_item_id' => $order_item_id ), + array( '%d' ) + ); + } else { + $wpdb->replace( + $wpdb->prefix . self::TABLE_NAME, + array( + 'order_item_id' => $order_item_id, + 'order_id' => $order->get_id(), + 'product_id' => $order_item->get_product_id( 'edit' ), + 'variation_id' => $order_item->get_variation_id( 'edit' ), + 'customer_id' => ( 0 < $order->get_customer_id( 'edit' ) ) ? $order->get_customer_id( 'edit' ) : null, + 'product_qty' => $order_item->get_quantity( 'edit' ) - $quantity_refunded, + 'product_net_revenue' => $order_item->get_subtotal( 'edit' ) - $amount_refunded, + 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), + ), + array( + '%d', + '%d', + '%d', + '%d', + '%d', + '%d', + '%f', + '%s', + ) + ); + } + } + } + + /** + * Get order refund items quantity and subtotal + * + * @param object $order WC Order object. + * @return array + */ + public static function get_order_refund_items( $order ) { + $refunds = $order->get_refunds(); + $refunded_line_items = array(); + foreach ( $refunds as $refund ) { + foreach ( $refund->get_items() as $refunded_item ) { + $line_item_id = wc_get_order_item_meta( $refunded_item->get_id(), '_refunded_item_id', true ); + if ( ! isset( $refunded_line_items[ $line_item_id ] ) ) { + $refunded_line_items[ $line_item_id ]['quantity'] = 0; + $refunded_line_items[ $line_item_id ]['subtotal'] = 0; + } + $refunded_line_items[ $line_item_id ]['quantity'] += absint( $refunded_item['quantity'] ); + $refunded_line_items[ $line_item_id ]['subtotal'] += abs( $refunded_item['subtotal'] ); + } + } + return $refunded_line_items; + } + } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-stats-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-stats-data-store.php index 37714b3674b..44ec6bcb364 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-stats-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-stats-data-store.php @@ -115,27 +115,29 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc $intervals_query = array(); $this->update_sql_query_params( $query_args, $totals_query, $intervals_query ); - $db_records_count = (int) $wpdb->get_var( - "SELECT COUNT(*) FROM ( - SELECT - {$intervals_query['select_clause']} AS time_interval - FROM - {$table_name} - {$intervals_query['from_clause']} - WHERE - 1=1 - {$intervals_query['where_time_clause']} - {$intervals_query['where_clause']} - GROUP BY - time_interval - ) AS t" - ); // WPCS: cache ok, DB call ok, unprepared SQL ok. + $db_intervals = $wpdb->get_col( + "SELECT + {$intervals_query['select_clause']} AS time_interval + FROM + {$table_name} + {$intervals_query['from_clause']} + WHERE + 1=1 + {$intervals_query['where_time_clause']} + {$intervals_query['where_clause']} + GROUP BY + time_interval" + ); // WPCS: cache ok, DB call ok, , unprepared SQL ok. - $total_pages = (int) ceil( $db_records_count / $intervals_query['per_page'] ); + $db_interval_count = count( $db_intervals ); + $expected_interval_count = WC_Admin_Reports_Interval::intervals_between( $query_args['after'], $query_args['before'], $query_args['interval'] ); + $total_pages = (int) ceil( $expected_interval_count / $intervals_query['per_page'] ); if ( $query_args['page'] < 1 || $query_args['page'] > $total_pages ) { return array(); } + $this->update_intervals_sql_params( $intervals_query, $query_args, $db_interval_count, $expected_interval_count ); + $totals = $wpdb->get_results( "SELECT {$selections} @@ -183,21 +185,41 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc $totals = (object) $this->cast_numbers( $totals[0] ); - $this->update_interval_boundary_dates( $query_args['after'], $query_args['before'], $query_args['interval'], $intervals ); - $this->create_interval_subtotals( $intervals ); - $data = (object) array( 'totals' => $totals, 'intervals' => $intervals, - 'total' => $db_records_count, + 'total' => $expected_interval_count, 'pages' => $total_pages, 'page_no' => (int) $query_args['page'], ); + if ( WC_Admin_Reports_Interval::intervals_missing( $expected_interval_count, $db_interval_count, $intervals_query['per_page'], $query_args['page'], $query_args['order'], $query_args['orderby'], count( $intervals ) ) ) { + $this->fill_in_missing_intervals( $db_intervals, $query_args['adj_after'], $query_args['adj_before'], $query_args['interval'], $data ); + $this->sort_intervals( $data, $query_args['orderby'], $query_args['order'] ); + $this->remove_extra_records( $data, $query_args['page'], $intervals_query['per_page'], $db_interval_count, $expected_interval_count, $query_args['orderby'] ); + } else { + $this->update_interval_boundary_dates( $query_args['after'], $query_args['before'], $query_args['interval'], $data->intervals ); + } + $this->create_interval_subtotals( $data->intervals ); + wp_cache_set( $cache_key, $data, $this->cache_group ); } return $data; } + /** + * Normalizes order_by clause to match to SQL query. + * + * @param string $order_by Order by option requeste by user. + * @return string + */ + protected function normalize_order_by( $order_by ) { + if ( 'date' === $order_by ) { + return 'time_interval'; + } + + return $order_by; + } + } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php index da563df8f66..c6581d3cd42 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php @@ -65,6 +65,15 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl $this->report_columns['tax_rate_id'] = $table_name . '.' . $this->report_columns['tax_rate_id']; } + /** + * Set up all the hooks for maintaining and populating table data. + */ + public static function init() { + add_action( 'save_post', array( __CLASS__, 'sync_order_taxes' ) ); + add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_taxes' ) ); + add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_taxes' ) ); + } + /** * Updates the database query with parameters used for Taxes report: categories and order status. * @@ -235,4 +244,49 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl return $order_by; } + /** + * Create or update an entry in the wc_order_tax_lookup table for an order. + * + * @param int $order_id Order ID. + * @return void + */ + public static function sync_order_taxes( $order_id ) { + global $wpdb; + $order = wc_get_order( $order_id ); + if ( ! $order ) { + return; + } + + if ( ! in_array( $order->get_status(), parent::get_report_order_statuses(), true ) ) { + $wpdb->delete( + $wpdb->prefix . self::TABLE_NAME, + array( 'order_id' => $order->get_id() ), + array( '%d' ) + ); + return; + } + + foreach ( $order->get_items( 'tax' ) as $tax_item ) { + $wpdb->replace( + $wpdb->prefix . self::TABLE_NAME, + array( + 'order_id' => $order->get_id(), + 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), + 'tax_rate_id' => $tax_item->get_rate_id(), + 'shipping_tax' => $tax_item->get_shipping_tax_total(), + 'order_tax' => $tax_item->get_tax_total(), + 'total_tax' => $tax_item->get_tax_total() + $tax_item->get_shipping_tax_total(), + ), + array( + '%d', + '%s', + '%d', + '%f', + '%f', + '%f', + ) + ); + } + } + } diff --git a/plugins/woocommerce-admin/includes/wc-admin-order-functions.php b/plugins/woocommerce-admin/includes/wc-admin-order-functions.php index 987ed683a0c..e69de29bb2d 100644 --- a/plugins/woocommerce-admin/includes/wc-admin-order-functions.php +++ b/plugins/woocommerce-admin/includes/wc-admin-order-functions.php @@ -1,192 +0,0 @@ -get_items() as $order_item ) { - // Shipping amount based on woocommerce code in includes/admin/meta-boxes/views/html-order-item(s).php - // distributed simply based on number of line items. - $order_items = $order->get_item_count(); - $refunded = $order->get_total_shipping_refunded(); - if ( $refunded > 0 ) { - $total_shipping_amount = $order->get_shipping_total() - $refunded; - } else { - $total_shipping_amount = $order->get_shipping_total(); - } - $shipping_amount = $total_shipping_amount / $order_items; - - // Shipping amount tax based on woocommerce code in includes/admin/meta-boxes/views/html-order-item(s).php - // distribute simply based on number of line items. - $shipping_tax_amount = 0; - // TODO: if WC is currently not tax enabled, but it was before (or vice versa), would this work correctly? - if ( wc_tax_enabled() ) { - $order_taxes = $order->get_taxes(); - $line_items_shipping = $order->get_items( 'shipping' ); - $total_shipping_tax_amount = 0; - foreach ( $line_items_shipping as $item_id => $item ) { - $tax_data = $item->get_taxes(); - if ( $tax_data ) { - foreach ( $order_taxes as $tax_item ) { - $tax_item_id = $tax_item->get_rate_id(); - $tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : ''; - $refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'shipping' ); - if ( $refunded ) { - $total_shipping_tax_amount += $tax_item_total - $refunded; - } else { - $total_shipping_tax_amount += $tax_item_total; - } - } - } - } - $shipping_tax_amount = $total_shipping_tax_amount / $order_items; - } - - // Tax amount. - // TODO: check if this calculates tax correctly with refunds. - $tax_amount = 0; - if ( wc_tax_enabled() ) { - $order_taxes = $order->get_taxes(); - $tax_data = $order_item->get_taxes(); - foreach ( $order_taxes as $tax_item ) { - $tax_item_id = $tax_item->get_rate_id(); - $tax_amount += isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : 0; - } - } - - $net_revenue = $order_item->get_subtotal( 'edit' ); - - // Coupon calculation based on woocommerce code in includes/admin/meta-boxes/views/html-order-item.php. - $coupon_amount = $order_item->get_subtotal( 'edit' ) - $order_item->get_total( 'edit' ); - - $wpdb->replace( - $wpdb->prefix . 'wc_order_product_lookup', - array( - 'order_item_id' => $order_item->get_id(), - 'order_id' => $order->get_id(), - 'product_id' => $order_item->get_product_id( 'edit' ), - 'variation_id' => $order_item->get_variation_id( 'edit' ), - 'customer_id' => ( 0 < $order->get_customer_id( 'edit' ) ) ? $order->get_customer_id( 'edit' ) : null, - 'product_qty' => $order_item->get_quantity( 'edit' ), - 'product_net_revenue' => $net_revenue, - 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), - 'price' => $order_item->get_subtotal( 'edit' ) / $order_item->get_quantity( 'edit' ), - 'coupon_amount' => $coupon_amount, - 'tax_amount' => $tax_amount, - 'shipping_amount' => $shipping_amount, - 'shipping_tax_amount' => $shipping_tax_amount, - 'product_gross_revenue' => $net_revenue + $tax_amount + $shipping_amount + $shipping_tax_amount, - ), - array( - '%d', - '%d', - '%d', - '%d', - '%d', - '%d', - '%f', - '%s', - '%f', - '%f', - '%f', - '%f', - '%f', - '%f', - ) - ); - } -} -// TODO: maybe replace these with woocommerce_create_order, woocommerce_update_order, woocommerce_trash_order, woocommerce_delete_order, as clean_post_cache might be called in other circumstances and trigger too many updates? -add_action( 'save_post', 'wc_admin_order_product_lookup_entry', 10, 1 ); -add_action( 'clean_post_cache', 'wc_admin_order_product_lookup_entry', 10, 1 ); - -/** - * Make an entry in the wc_order_tax_lookup table for an order. - * - * @since 3.5.0 - * @param int $order_id Order ID. - * @return void - */ -function wc_order_tax_lookup_entry( $order_id ) { - global $wpdb; - $order = wc_get_order( $order_id ); - if ( ! $order ) { - return; - } - foreach ( $order->get_items( 'tax' ) as $tax_item ) { - $wpdb->replace( - $wpdb->prefix . 'wc_order_tax_lookup', - array( - 'order_id' => $order->get_id(), - 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), - 'tax_rate_id' => $tax_item->get_rate_id(), - 'shipping_tax' => $tax_item->get_shipping_tax_total(), - 'order_tax' => $tax_item->get_tax_total(), - 'total_tax' => $tax_item->get_tax_total() + $tax_item->get_shipping_tax_total(), - ), - array( - '%d', - '%s', - '%d', - '%f', - '%f', - '%f', - ) - ); - } -} -add_action( 'save_post', 'wc_order_tax_lookup_entry', 10, 1 ); -add_action( 'clean_post_cache', 'wc_order_tax_lookup_entry', 10, 1 ); - -/** - * Make an entry in the wc_order_coupon_lookup table for an order. - * - * @since 3.5.0 - * @param int $order_id Order ID. - * @return void - */ -function wc_order_coupon_lookup_entry( $order_id ) { - global $wpdb; - - $order = wc_get_order( $order_id ); - if ( ! $order ) { - return; - } - - $coupon_items = $order->get_items( 'coupon' ); - foreach ( $coupon_items as $coupon_item ) { - $wpdb->replace( - $wpdb->prefix . 'wc_order_coupon_lookup', - array( - 'order_id' => $order_id, - 'coupon_id' => wc_get_coupon_id_by_code( $coupon_item->get_code() ), - 'discount_amount' => $coupon_item->get_discount(), - 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), - ), - array( - '%d', - '%d', - '%f', - '%s', - ) - ); - } -} -add_action( 'save_post', 'wc_order_coupon_lookup_entry', 10, 1 ); -add_action( 'clean_post_cache', 'wc_order_coupon_lookup_entry', 10, 1 ); diff --git a/plugins/woocommerce-admin/lib/admin.php b/plugins/woocommerce-admin/lib/admin.php index 2adbb706106..b44ac05158f 100644 --- a/plugins/woocommerce-admin/lib/admin.php +++ b/plugins/woocommerce-admin/lib/admin.php @@ -214,6 +214,16 @@ function wc_admin_enqueue_script() { wp_enqueue_script( WC_ADMIN_APP ); wp_enqueue_style( WC_ADMIN_APP ); + + // Use server-side detection to prevent unneccessary stylesheet loading in other browsers. + $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : ''; // WPCS: sanitization ok. + preg_match( '/MSIE (.*?);/', $user_agent, $matches ); + if ( count( $matches ) < 2 ) { + preg_match( '/Trident\/\d{1,2}.\d{1,2}; rv:([0-9]*)/', $user_agent, $matches ); + } + if ( count( $matches ) > 1 ) { + wp_enqueue_style( 'wc-components-ie' ); + } } add_action( 'admin_enqueue_scripts', 'wc_admin_enqueue_script' ); diff --git a/plugins/woocommerce-admin/lib/client-assets.php b/plugins/woocommerce-admin/lib/client-assets.php index d8f7a440464..8e876376ceb 100644 --- a/plugins/woocommerce-admin/lib/client-assets.php +++ b/plugins/woocommerce-admin/lib/client-assets.php @@ -102,6 +102,13 @@ function wc_admin_register_script() { filemtime( wc_admin_dir_path( 'dist/components/style.css' ) ) ); + wp_register_style( + 'wc-components-ie', + wc_admin_url( 'dist/components/ie.css' ), + array( 'wp-edit-blocks' ), + filemtime( wc_admin_dir_path( 'dist/components/ie.css' ) ) + ); + wp_register_style( WC_ADMIN_APP, wc_admin_url( "dist/{$entry}/style.css" ), diff --git a/plugins/woocommerce-admin/package-lock.json b/plugins/woocommerce-admin/package-lock.json index 9caabdd71da..8bafe1db940 100644 --- a/plugins/woocommerce-admin/package-lock.json +++ b/plugins/woocommerce-admin/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/cli": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.2.0.tgz", - "integrity": "sha512-FLteTkEoony0DX8NbnT51CmwmLBzINdlXmiJCSqCLmqWCDA/xk8EITPWqwDnVLbuK0bsZONt/grqHnQzQ15j0Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.2.3.tgz", + "integrity": "sha512-bfna97nmJV6nDJhXNPeEfxyMjWnt6+IjUAaDPiYRTBlm8L41n8nvw6UAqUCbvpFfU246gHPxW7sfWwqtF4FcYA==", "dev": true, "requires": { "chokidar": "^2.0.3", @@ -39,18 +39,18 @@ } }, "@babel/core": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.2.0.tgz", - "integrity": "sha512-7pvAdC4B+iKjFFp9Ztj0QgBndJ++qaMeonT185wAqUnhipw8idm9Rv1UMyBuKtYjfl6ORNkgEgcsYLfHX/GpLw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.2.2.tgz", + "integrity": "sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.0", + "@babel/generator": "^7.2.2", "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.2.0", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.2.0", + "@babel/parser": "^7.2.2", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.2.2", + "@babel/types": "^7.2.2", "convert-source-map": "^1.1.0", "debug": "^4.1.0", "json5": "^2.1.0", @@ -71,7 +71,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -233,13 +233,13 @@ } }, "@babel/helper-replace-supers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz", - "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", + "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", "requires": { "@babel/helper-member-expression-to-functions": "^7.0.0", "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.1.0", + "@babel/traverse": "^7.2.3", "@babel/types": "^7.0.0" } }, @@ -293,9 +293,9 @@ } }, "@babel/parser": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.2.tgz", - "integrity": "sha512-UNTmQ5cSLDeBGBl+s7JeowkqIHgmFAGBnLDdIzFmUNSuS5JF0XBcN59jsh/vJO/YjfsBqMxhMjoFGmNExmf0FA==" + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz", + "integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.2.0", @@ -648,9 +648,9 @@ } }, "@babel/preset-env": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.2.0.tgz", - "integrity": "sha512-haGR38j5vOGVeBatrQPr3l0xHbs14505DcM57cbJy48kgMFvvHHoYEhHuRV+7vi559yyAUAVbTWzbK/B/pzJng==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.2.3.tgz", + "integrity": "sha512-AuHzW7a9rbv5WXmvGaPX7wADxFkZIqKlbBh1dmZUQp4iwiPpkE/Qnrji6SC4UQCQzvWY/cpHET29eUhXS9cLPw==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", @@ -723,15 +723,15 @@ } }, "@babel/traverse": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.2.tgz", - "integrity": "sha512-E5Bn9FSwHpSkUhthw/XEuvFZxIgrqb9M8cX8j5EUQtrUG5DQUy6bFyl7G7iQ1D1Czudor+xkmp81JbLVVM0Sjg==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", + "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", "requires": { "@babel/code-frame": "^7.0.0", "@babel/generator": "^7.2.2", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.2", + "@babel/parser": "^7.2.3", "@babel/types": "^7.2.2", "debug": "^4.1.0", "globals": "^11.1.0", @@ -756,16 +756,21 @@ "@babel/runtime-corejs2": "^7.1.5" } }, + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==" + }, "@lerna/add": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.6.0.tgz", - "integrity": "sha512-aFVekkHMno3hj1Vg3EiIpAwrZ4g34i8z4KrCx7ATY6BRuxVT4Nt/Nk3l2k6gEOq3tWUDtUctLHxIAo14FI8sng==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.7.2.tgz", + "integrity": "sha512-/kCuyytOEmYcqpbU8MhHc2/3bPJjEx+qq7SOdb0cCDG+QcJ/oSsDCZ3xVHxhyLRYAoRlKBch3DiBmY4BeIm0Ag==", "dev": true, "requires": { - "@lerna/bootstrap": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/bootstrap": "^3.7.2", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", - "@lerna/npm-conf": "^3.4.1", + "@lerna/npm-conf": "^3.7.0", "@lerna/validation-error": "^3.6.0", "dedent": "^0.7.0", "libnpm": "^2.0.1", @@ -785,23 +790,23 @@ } }, "@lerna/bootstrap": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.6.0.tgz", - "integrity": "sha512-z6rZQw/aLEN+ragWRYqIIVwA9rDv3QtmRc5VyIRrlV/JiuGpq67FcSR6BrCMc/A7UJ9Kx95+bESm/HUwheKoiQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.7.2.tgz", + "integrity": "sha512-yVjr450UivC7gbIh3GZowJ6bzPy/xC75bduq2Zm+jdIksjM/8SA3HRXWNothaSyZWudV+WY+cy6MvwrtFe8Kbg==", "dev": true, "requires": { "@lerna/batch-packages": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", "@lerna/has-npm-version": "^3.3.0", - "@lerna/npm-conf": "^3.4.1", "@lerna/npm-install": "^3.6.0", "@lerna/package-graph": "^3.6.0", + "@lerna/pulse-till-done": "^3.7.1", "@lerna/rimraf-dir": "^3.6.0", - "@lerna/run-lifecycle": "^3.6.0", + "@lerna/run-lifecycle": "^3.7.1", "@lerna/run-parallel-batches": "^3.0.0", - "@lerna/symlink-binary": "^3.6.0", - "@lerna/symlink-dependencies": "^3.6.0", + "@lerna/symlink-binary": "^3.7.2", + "@lerna/symlink-dependencies": "^3.7.2", "@lerna/validation-error": "^3.6.0", "dedent": "^0.7.0", "get-port": "^3.2.0", @@ -816,16 +821,16 @@ } }, "@lerna/changed": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.6.0.tgz", - "integrity": "sha512-L1SXTtQrsv+4F5Knw5sW/nGnMJq+bbOzhZX2srJ10WsuHuzk3cJWAi7dVEsS3RPKUw9DWOuHKy86o3v6byEiqA==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.8.0.tgz", + "integrity": "sha512-IeOxB+nwGFpAuEgUi9FeP19hj6Abp1aNCeMjS9/KpOxrSGt3ejKlSKY83lwqDPbb6OnthQTRBlodWZpSiSPWqg==", "dev": true, "requires": { "@lerna/collect-updates": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/listable": "^3.6.0", "@lerna/output": "^3.6.0", - "@lerna/version": "^3.6.0" + "@lerna/version": "^3.8.0" } }, "@lerna/check-working-tree": { @@ -885,28 +890,19 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, "@lerna/clean": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.6.0.tgz", - "integrity": "sha512-4LodI/jh8IEYtqnrY/OFSpWn5YfDWoDv+5QjiJpd91EjW9vjmkvyhzQ5fG9KtltwgYVn/NJ5zlI1WfmMEXvFFQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.7.2.tgz", + "integrity": "sha512-BhuPnAWQa2av6hSE8imbOhenUnveSp0VDO1X0jzC1EX+K6sBCubbowM13kYi+N0qUd2kdeatBNwmafzkBZ3LcQ==", "dev": true, "requires": { - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", "@lerna/prompt": "^3.6.0", + "@lerna/pulse-till-done": "^3.7.1", "@lerna/rimraf-dir": "^3.6.0", "p-map": "^1.2.0", "p-map-series": "^1.0.0", @@ -945,13 +941,13 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -968,6 +964,15 @@ "locate-path": "^3.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -1005,20 +1010,20 @@ } }, "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "^0.10.0", + "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1085,14 +1090,14 @@ } }, "@lerna/command": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.6.0.tgz", - "integrity": "sha512-BGpXaY2WrxPcIiZX0aATO2HQBatvYT7Qy46lqMnV9RrTePYJ1PPbX1nMzLXSxgrnnlTcTwJNEkw/TL9Xzrph7Q==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.7.2.tgz", + "integrity": "sha512-WtBnlvQfzKmnc2i3g+GLazx7pUXwbzASiXHy4j1CoC0w90H42LUqhwJICro4VhnE8xi38BNhcH/+xFNiHX5ERA==", "dev": true, "requires": { "@lerna/child-process": "^3.3.0", "@lerna/package-graph": "^3.6.0", - "@lerna/project": "^3.6.0", + "@lerna/project": "^3.7.2", "@lerna/validation-error": "^3.6.0", "@lerna/write-log-file": "^3.6.0", "dedent": "^0.7.0", @@ -1138,16 +1143,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -1195,28 +1190,18 @@ "requires": { "graceful-fs": "^4.1.6" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, "@lerna/create": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.6.0.tgz", - "integrity": "sha512-21OunW25Y3Q/oynqWVk0znQFBvZ5tHyLPhzkJeomGmOj0il1RdOUiChu9G9AYsCaLDwBFR0ZFqvTgJ5iw/eaIg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.7.2.tgz", + "integrity": "sha512-eE6i4mVi5CefQ8Mw4WhkX9GcgiDllfEYfMq3LDMCtBH4pdzXO9oNG2p1J7bbwKgCFqhmKB4nr5FTFhijOIMRRw==", "dev": true, "requires": { "@lerna/child-process": "^3.3.0", - "@lerna/command": "^3.6.0", - "@lerna/npm-conf": "^3.4.1", + "@lerna/command": "^3.7.2", + "@lerna/npm-conf": "^3.7.0", "@lerna/validation-error": "^3.6.0", "camelcase": "^4.1.0", "dedent": "^0.7.0", @@ -1246,7 +1231,7 @@ }, "globby": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-8.0.1.tgz", "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { @@ -1331,26 +1316,26 @@ } }, "@lerna/diff": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.6.0.tgz", - "integrity": "sha512-p5+VyYKuAnw6NFVrT4s9eBubFZEYlJmiR1mdVlwNtohqS86gERjrPtI0unUK/pxFKb1U2ZNo4fhSlPd+pLwfHg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.7.2.tgz", + "integrity": "sha512-BVcceQHxwr0hIO4hZ8Udeb1Afn2opDiMXSh3dEyV7kcbYlgc66AxsviVPr4txGP/p8uRlzBUDzgHShVMplMGcg==", "dev": true, "requires": { "@lerna/child-process": "^3.3.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/validation-error": "^3.6.0", "libnpm": "^2.0.1" } }, "@lerna/exec": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.6.0.tgz", - "integrity": "sha512-lwLYASpS8FoQpVYLBpoZlS7bpzkO9pD3D9XeDDKZBodDhdZeCEx2Md2CxZU1RKYDSVIXA8oObvlUh1FEhRQv2w==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.7.2.tgz", + "integrity": "sha512-oEm3EbSxXeMguqC+ekXaBlRmo/aaJc2BcWPHrd+5+9evHhHo/7oOu/xXmbhJYCgZytGkJ6BrX3F9XhWnC+14wg==", "dev": true, "requires": { "@lerna/batch-packages": "^3.6.0", "@lerna/child-process": "^3.3.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", "@lerna/run-parallel-batches": "^3.0.0", "@lerna/validation-error": "^3.6.0" @@ -1387,6 +1372,69 @@ "libnpm": "^2.0.1" } }, + "@lerna/get-packed": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.7.0.tgz", + "integrity": "sha512-yuFtjsUZIHjeIvIYQ/QuytC+FQcHwo3peB+yGBST2uWCLUCR5rx6knoQcPzbxdFDCuUb5IFccFGd3B1fHFg3RQ==", + "dev": true, + "requires": { + "fs-extra": "^7.0.0", + "ssri": "^6.0.1", + "tar": "^4.4.8" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, "@lerna/global-options": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-3.1.3.tgz", @@ -1404,14 +1452,15 @@ } }, "@lerna/import": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.6.0.tgz", - "integrity": "sha512-8jxNRbAaa4mvMJr0u+sy75gMFPyWfxLHEp+pDs73x1oqMZhpS8O5901QMnpZyRyOvJRhoBJd5hBX2dpsLxC6Xw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.7.2.tgz", + "integrity": "sha512-TGTYjhzDGLEqc9imWOi/fvIbZdmVxfV71OFB6AS98N9KQE68bbpttehQqCUIPATReVuzPUzxEiF3tMnKd7iEqg==", "dev": true, "requires": { "@lerna/child-process": "^3.3.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/prompt": "^3.6.0", + "@lerna/pulse-till-done": "^3.7.1", "@lerna/validation-error": "^3.6.0", "dedent": "^0.7.0", "fs-extra": "^7.0.0", @@ -1441,13 +1490,13 @@ } }, "@lerna/init": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.6.0.tgz", - "integrity": "sha512-MTLy3rmMdvpXRmDdoYiVPx7I8sXH4dquq/0MxntL5VxSVh/ZS1HsbrjyRqpdkUKWD9QguxR/w0pzOjVvCeM8CQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.7.2.tgz", + "integrity": "sha512-840Az0GtyepX7/WH3QvOQDZJCEGFf4IykjjFuCLF+23+Od8Wxn3QCsp4Yn/+HKi/w7bSpsCHJ6xQG208dygfdw==", "dev": true, "requires": { "@lerna/child-process": "^3.3.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "fs-extra": "^7.0.0", "p-map": "^1.2.0", "write-json-file": "^2.3.0" @@ -1476,25 +1525,25 @@ } }, "@lerna/link": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.6.0.tgz", - "integrity": "sha512-Xk8TTAE4EWGyhxLuPxWdyS7i7vfsM5igb6tEyhZm94XUdlA4PmMOYe25BfO7SM/9LYroFknZeDyWAebye3r+PA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.7.2.tgz", + "integrity": "sha512-iwxftHVPknb+RXtD7257/FR4DYiCxJRxqo6z/YGlojWjehYRfbK7tJe4xzRzxepIXAE8+ooQFqQ73m0/ozk6kQ==", "dev": true, "requires": { - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/package-graph": "^3.6.0", - "@lerna/symlink-dependencies": "^3.6.0", + "@lerna/symlink-dependencies": "^3.7.2", "p-map": "^1.2.0", "slash": "^1.0.0" } }, "@lerna/list": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.6.0.tgz", - "integrity": "sha512-hlQOJkg8K3XXUVXotofP71XsgkhXkkmU/EkqlNg15D78MjzhT+p1wCbG5m89K3tzvjcWVeZwU6L0elaOIXVyCw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.7.2.tgz", + "integrity": "sha512-yup9KivG31APzr+C96up83m1llqs62spsLuKkinwVUhL5mobhDscT6QwIWTJPRJ8Bbmi++SdXGLfGFkYmgujzQ==", "dev": true, "requires": { - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", "@lerna/listable": "^3.6.0", "@lerna/output": "^3.6.0" @@ -1524,9 +1573,9 @@ } }, "@lerna/npm-conf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.4.1.tgz", - "integrity": "sha512-i9G6DnbCqiAqxKx2rSXej/n14qxlV/XOebL6QZonxJKzNTB+Q2wglnhTXmfZXTPJfoqimLaY4NfAEtbOXRWOXQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.7.0.tgz", + "integrity": "sha512-+WSMDfPKcKzMfqq283ydz9RRpOU6p9wfx0wy4hVSUY/6YUpsyuk8SShjcRtY8zTM5AOrxvFBuuV90H4YpZ5+Ng==", "dev": true, "requires": { "config-chain": "^1.1.11", @@ -1542,13 +1591,13 @@ } }, "@lerna/npm-dist-tag": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.6.0.tgz", - "integrity": "sha512-qX6IfQPX9Tum1LRjvjgj/yr2FYbc9dfHyeh7RI9zJ8pGncWbksBmnMcvoxF0Eu4+d7MjjIGfEnIp9LIl4MHSIA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.7.1.tgz", + "integrity": "sha512-caUfA1L6wFl/nvIkk4q7qbFHZSnF2P8zf3Xk7vJMolRybYbj+WT1gYb5C446qPIF75p7JtFu3C/AJzwzdbljCw==", "dev": true, "requires": { - "libnpm": "^2.0.1", - "npm-registry-fetch": "^3.8.0" + "figgy-pudding": "^3.5.1", + "libnpm": "^2.0.1" } }, "@lerna/npm-install": { @@ -1588,18 +1637,15 @@ } }, "@lerna/npm-publish": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.6.0.tgz", - "integrity": "sha512-k4yF8ursajoGRlJeRh7xdeGN0HV/ALt5qImUnpTliux0213jqxA0YigiD8WSaXpvSqxSFyvh38DbJhhy9q+NuQ==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.7.1.tgz", + "integrity": "sha512-3Tv4UWD+1Wz1Eqc7/8eEvAHL5c2pTx+rOKYMEc6P5Z1glN1+TfIfPckPAX0H2xg44yTCh1KGJSSBpJQl68QqIQ==", "dev": true, "requires": { - "@lerna/child-process": "^3.3.0", - "@lerna/get-npm-exec-opts": "^3.6.0", - "@lerna/has-npm-version": "^3.3.0", - "@lerna/log-packed": "^3.6.0", + "@lerna/run-lifecycle": "^3.7.1", + "figgy-pudding": "^3.5.1", "fs-extra": "^7.0.0", - "libnpm": "^2.0.1", - "p-map": "^1.2.0" + "libnpm": "^2.0.1" }, "dependencies": { "fs-extra": { @@ -1644,14 +1690,90 @@ "libnpm": "^2.0.1" } }, + "@lerna/pack-directory": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-3.7.2.tgz", + "integrity": "sha512-yAZNSdAsBD26as+Il1l5R0fQaI6vTJqyNeK181V2vf34+KC0NX9TVaM+/Ht28QpK+3SaD2tvVP1T7OP2w0g2qg==", + "dev": true, + "requires": { + "@lerna/get-packed": "^3.7.0", + "@lerna/package": "^3.7.2", + "@lerna/run-lifecycle": "^3.7.1", + "figgy-pudding": "^3.5.1", + "libnpm": "^2.0.1", + "npm-packlist": "^1.1.12", + "tar": "^4.4.8", + "temp-write": "^3.4.0" + }, + "dependencies": { + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, "@lerna/package": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.6.0.tgz", - "integrity": "sha512-XbXcjwPKA1V640mqjEicpBriO6QcNtocdfLAtEUP4uCKkRx5r9h7DdznQMCoSJYJF6Gh/PpLokPUItfMhJP3Hg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.7.2.tgz", + "integrity": "sha512-8A5hN2CekM1a0Ix4VUO/g+REo+MsnXb8lnQ0bGjr1YGWzSL5NxYJ0Z9+0pwTfDpvRDYlFYO0rMVwBUW44b4dUw==", "dev": true, "requires": { "libnpm": "^2.0.1", + "load-json-file": "^4.0.0", "write-pkg": "^3.1.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "@lerna/package-graph": { @@ -1666,12 +1788,12 @@ } }, "@lerna/project": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.6.0.tgz", - "integrity": "sha512-pEOZF1igGFqs+qWog6cJWqVyBUX21xSqrlcgeN0yzqzI36VMHozmf/u7dgclIb5MylWk5Yp87KCKswBF4hrcuQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.7.2.tgz", + "integrity": "sha512-YNJw61G4YrnwW0P1NAR/bd/kfDdK+WPI5YH10AHsG1TXBFV9hBusjB7MROmobYbln7zNWJJ3PQmXtWv134aaRQ==", "dev": true, "requires": { - "@lerna/package": "^3.6.0", + "@lerna/package": "^3.7.2", "@lerna/validation-error": "^3.6.0", "cosmiconfig": "^5.0.2", "dedent": "^0.7.0", @@ -1697,7 +1819,7 @@ }, "globby": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-8.0.1.tgz", "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { @@ -1833,27 +1955,30 @@ } }, "@lerna/publish": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.6.0.tgz", - "integrity": "sha512-F2bT96ZS7NJfid6T4a6TSanpVUQ4VOuhjPBPX2hagt5gnocm7lluvAFR7dl/cbEgmKIg2zJQnfAPTYjrtxXMVg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.8.0.tgz", + "integrity": "sha512-EJDF6oPySIHQRre9KMMqtltrPReuBT7Po72W6OQxCUmCjqDyUd6884lhqFHOgbtOl1axrVVaSOpxCU1m+SLNgA==", "dev": true, "requires": { "@lerna/batch-packages": "^3.6.0", "@lerna/check-working-tree": "^3.6.0", "@lerna/child-process": "^3.3.0", "@lerna/collect-updates": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/describe-ref": "^3.6.0", - "@lerna/get-npm-exec-opts": "^3.6.0", - "@lerna/npm-conf": "^3.4.1", - "@lerna/npm-dist-tag": "^3.6.0", - "@lerna/npm-publish": "^3.6.0", + "@lerna/log-packed": "^3.6.0", + "@lerna/npm-conf": "^3.7.0", + "@lerna/npm-dist-tag": "^3.7.1", + "@lerna/npm-publish": "^3.7.1", "@lerna/output": "^3.6.0", + "@lerna/pack-directory": "^3.7.2", "@lerna/prompt": "^3.6.0", - "@lerna/run-lifecycle": "^3.6.0", + "@lerna/pulse-till-done": "^3.7.1", + "@lerna/run-lifecycle": "^3.7.1", "@lerna/run-parallel-batches": "^3.0.0", "@lerna/validation-error": "^3.6.0", - "@lerna/version": "^3.6.0", + "@lerna/version": "^3.8.0", + "figgy-pudding": "^3.5.1", "fs-extra": "^7.0.0", "libnpm": "^2.0.1", "npm-registry-fetch": "^3.8.0", @@ -1886,6 +2011,15 @@ } } }, + "@lerna/pulse-till-done": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-3.7.1.tgz", + "integrity": "sha512-MzpesZeW3Mc+CiAq4zUt9qTXI9uEBBKrubYHE36voQTSkHvu/Rox6YOvfUr+U7P6k8frFPeCgGpfMDTLhiqe6w==", + "dev": true, + "requires": { + "libnpm": "^2.0.1" + } + }, "@lerna/resolve-symlink": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-3.6.0.tgz", @@ -1932,13 +2066,13 @@ } }, "@lerna/run": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.6.0.tgz", - "integrity": "sha512-OYa5pQTOiES/h9rg8vwnt0nYU/wLKUQmFYhMUxdX3lXYpoIcQ28PR7qPG1CVhex4KAU2OW42a7vnm5MAOoScDg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.7.2.tgz", + "integrity": "sha512-FwBjcrtYSFyvY2YXJ8GoI9VNv2UElUbVra5+iTF1DgQh37RmK0ZCODkfXp6PYyUszHkgCRuJqhK0+yMWRJo61w==", "dev": true, "requires": { "@lerna/batch-packages": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/filter-options": "^3.6.0", "@lerna/npm-run-script": "^3.6.0", "@lerna/output": "^3.6.0", @@ -1949,12 +2083,13 @@ } }, "@lerna/run-lifecycle": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.6.0.tgz", - "integrity": "sha512-/1+vAZnckgKwHVgWG0plVO24erNWUduz9htMOO9wuOfglTnHlMRqDc3s9B/OIKxGDkyzEvxqzfzq3c6JqEolRQ==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.7.1.tgz", + "integrity": "sha512-kE6w8d8Qde+ewZaDNIz4zhwde8s/i8vbbOsGDlR/Vw/9nqlmtj2YBZaS262NtWj83N04dtdYr4FVj51thciGQw==", "dev": true, "requires": { - "@lerna/npm-conf": "^3.4.1", + "@lerna/npm-conf": "^3.7.0", + "figgy-pudding": "^3.5.1", "libnpm": "^2.0.1" } }, @@ -1969,16 +2104,15 @@ } }, "@lerna/symlink-binary": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.6.0.tgz", - "integrity": "sha512-h69AQBBWgZOEzQ1RJEYQ7Ou6llrJNhNNkpqT6k8qSWZ93iXyFmLE4hWoxMXXHFmxmQ0CqjEYKmeLV1Dr5DKT4g==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.7.2.tgz", + "integrity": "sha512-xS7DdBXNQgfgrhBe2Jz27+S65yxBfnl+Xi+grvlqoEGVk7b8kt2VcBtui/XgL6AAaTg6f9szj4LUnwC/oX6S1Q==", "dev": true, "requires": { "@lerna/create-symlink": "^3.6.0", - "@lerna/package": "^3.6.0", + "@lerna/package": "^3.7.2", "fs-extra": "^7.0.0", - "p-map": "^1.2.0", - "read-pkg": "^3.0.0" + "p-map": "^1.2.0" }, "dependencies": { "fs-extra": { @@ -2000,72 +2134,18 @@ "requires": { "graceful-fs": "^4.1.6" } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true } } }, "@lerna/symlink-dependencies": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.6.0.tgz", - "integrity": "sha512-mLpbWLidAU5Xi7bc9Fj8Yt/9XvDczzWocnS/yEe0E6RqWXh2KK+4VR9H24rLywBAWTv2s4GEXrb/ofbPb8gwBQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.7.2.tgz", + "integrity": "sha512-53fZUGQ+QLr5P7I9/pqFmCizLo4Q/Jz5ETd1NURO2+eABGdYuTnuvtqyGku+eOr9A4gYDaVmg50KEpsOXq9TWg==", "dev": true, "requires": { "@lerna/create-symlink": "^3.6.0", "@lerna/resolve-symlink": "^3.6.0", - "@lerna/symlink-binary": "^3.6.0", + "@lerna/symlink-binary": "^3.7.2", "fs-extra": "^7.0.0", "p-finally": "^1.0.0", "p-map": "^1.2.0", @@ -2110,20 +2190,20 @@ } }, "@lerna/version": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.6.0.tgz", - "integrity": "sha512-V1f3fNM5ELGHmF824Wc8ah505SMpfiBqOHAIiW+u9soH/3W/t256c1P9UeaDh5blWAk3HeZMzbpRZ9Nlpf6aQA==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.8.0.tgz", + "integrity": "sha512-c+TNPzlyv0dgDpgMu87CPauk8R2jZwwftgQarHOCGbEZ0ClXqLFTEAKxvLpzprlt+kH3goIWYNQrZiJflpMOCA==", "dev": true, "requires": { "@lerna/batch-packages": "^3.6.0", "@lerna/check-working-tree": "^3.6.0", "@lerna/child-process": "^3.3.0", "@lerna/collect-updates": "^3.6.0", - "@lerna/command": "^3.6.0", + "@lerna/command": "^3.7.2", "@lerna/conventional-commits": "^3.6.0", "@lerna/output": "^3.6.0", "@lerna/prompt": "^3.6.0", - "@lerna/run-lifecycle": "^3.6.0", + "@lerna/run-lifecycle": "^3.7.1", "@lerna/validation-error": "^3.6.0", "chalk": "^2.3.1", "dedent": "^0.7.0", @@ -2192,9 +2272,9 @@ "integrity": "sha512-59/mWwU7sXHfoU2kI3RcWRki2Jjbz5nEVJNBN4MUyIhPjXTebAcZqgsQACvlk+sjKVOTMEMHcrFrKQbaxz/1Dw==" }, "@types/node": { - "version": "10.12.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", - "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==" + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, "@webassemblyjs/ast": { "version": "1.7.11", @@ -2836,7 +2916,7 @@ }, "eslint": { "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "requires": { "ajv": "^5.3.0", @@ -2888,7 +2968,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "globals": { @@ -3044,7 +3124,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "requires": { "acorn": "^3.0.4" @@ -3052,7 +3132,7 @@ "dependencies": { "acorn": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" } } @@ -3135,7 +3215,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" }, "ansi-regex": { @@ -3237,7 +3317,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -3255,7 +3335,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -3449,7 +3529,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -3464,7 +3544,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -3483,7 +3563,7 @@ "dependencies": { "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" } } @@ -3524,7 +3604,7 @@ }, "array-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, "array-find-index": { @@ -3633,7 +3713,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -3705,13 +3785,13 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "autoprefixer": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.2.tgz", - "integrity": "sha512-tYQYJvZvqlJCzF+BLC//uAcdT/Yy4ik9bwZRXr/EehUJ/bjjpTthsWTy8dpowdoIE1sLCDf1ch4Eb2cOSzZC9w==", + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.3.tgz", + "integrity": "sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ==", "dev": true, "requires": { - "browserslist": "^4.3.5", - "caniuse-lite": "^1.0.30000914", + "browserslist": "^4.3.6", + "caniuse-lite": "^1.0.30000921", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", "postcss": "^7.0.6", @@ -3773,7 +3853,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -3790,7 +3870,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" } } @@ -3843,7 +3923,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" } } @@ -3911,7 +3991,7 @@ }, "babel-plugin-istanbul": { "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "requires": { "babel-plugin-syntax-object-rest-spread": "^6.13.0", @@ -3927,13 +4007,13 @@ }, "babel-plugin-syntax-class-properties": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", "dev": true }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" }, "babel-plugin-transform-class-properties": { @@ -3948,6 +4028,15 @@ "babel-template": "^6.24.1" } }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, "babel-polyfill": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", @@ -4204,9 +4293,9 @@ } }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, "bin-links": { @@ -4230,7 +4319,7 @@ }, "bindings": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "resolved": "http://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", "dev": true }, @@ -4325,14 +4414,14 @@ "dependencies": { "resolve": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" } } }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -4369,7 +4458,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -4434,14 +4523,14 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -4492,7 +4581,7 @@ }, "cacache": { "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "resolved": "http://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { @@ -4567,14 +4656,14 @@ "dependencies": { "callsites": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" } } }, "callsites": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" }, "camelcase": { @@ -4593,9 +4682,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000921", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000921.tgz", - "integrity": "sha512-Bu09ciy0lMWLgpYC77I0YGuI8eFRBPPzaSOYJK1jTI64txCphYCqnWbxJYjHABYVt/TYX/p3jNjLBR87u1Bfpw==" + "version": "1.0.30000925", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000925.tgz", + "integrity": "sha512-zcYupoUxtW46rOikuDF7vfL9N1Qe9ZuUBTz3n3q8fFsoJIs/h9UN6Vg/0QpjsmvImXw9mVc3g+ZBfqvUz/iALA==" }, "capture-exit": { "version": "1.2.0", @@ -5007,7 +5096,7 @@ }, "color": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "resolved": "http://registry.npmjs.org/color/-/color-0.11.4.tgz", "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", "dev": true, "requires": { @@ -5031,7 +5120,7 @@ }, "color-string": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", "dev": true, "requires": { @@ -5039,9 +5128,10 @@ } }, "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=" + "version": "1.1.2", + "resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true }, "columnify": { "version": "1.5.4", @@ -5062,9 +5152,9 @@ } }, "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" }, "commondir": { "version": "1.0.1", @@ -5115,7 +5205,7 @@ }, "concat-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "resolved": "http://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { "buffer-from": "^1.0.0", @@ -5126,7 +5216,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -5140,7 +5230,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -5185,13 +5275,13 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -5208,6 +5298,15 @@ "locate-path": "^3.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", @@ -5251,20 +5350,20 @@ } }, "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "^0.10.0", + "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -5407,9 +5506,9 @@ } }, "connect-livereload": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.0.tgz", - "integrity": "sha1-+fAJh0rWg3GDr7FwtMTjhXodfOs=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", "dev": true }, "console-browserify": { @@ -5602,7 +5701,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -5716,7 +5815,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -5821,7 +5920,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -5940,9 +6039,9 @@ } }, "core-js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.0.tgz", - "integrity": "sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==" }, "core-util-is": { "version": "1.0.2", @@ -6007,7 +6106,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -6020,7 +6119,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -6131,17 +6230,17 @@ } }, "css-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.0.0.tgz", - "integrity": "sha512-3Fq8HJYs7ruBiDpJA/w2ZROtivA769ePuH3/vgPdOB+FQiotErJ7VJYRZq86SPRVFaccn1wEktUnaaUyf+Uslw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.0.tgz", + "integrity": "sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q==", "dev": true, "requires": { "icss-utils": "^4.0.0", - "loader-utils": "^1.0.2", + "loader-utils": "^1.2.1", "lodash": "^4.17.11", "postcss": "^7.0.6", "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^2.0.2", + "postcss-modules-local-by-default": "^2.0.3", "postcss-modules-scope": "^2.0.0", "postcss-modules-values": "^2.0.0", "postcss-value-parser": "^3.3.0", @@ -6169,7 +6268,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "requires": { "boolbase": "~1.0.0", @@ -6191,13 +6290,13 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, "regexpu-core": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { @@ -6208,13 +6307,13 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, "regjsparser": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { @@ -6262,9 +6361,9 @@ "dev": true }, "d3-array": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.0.2.tgz", - "integrity": "sha512-dbjbKhMdnTW6ToWsopRs4/+ZPOsqQE1QeeoUEvzIqhdkT29zzAUcUh8HMb92tTITVlbW/G0UBz4ryBqC2RTUIA==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.0.3.tgz", + "integrity": "sha512-C7g4aCOoJa+/K5hPVqZLG8wjYHsTUROTk7Z1Ep9F4P5l+WVrvV0+6nAZ1wKTRLMhFWpGbozxUpyjIPZYAaLi+g==" }, "d3-axis": { "version": "1.0.12", @@ -6379,7 +6478,7 @@ }, "dashify": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz", + "resolved": "http://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz", "integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4=", "dev": true }, @@ -6435,7 +6534,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -6460,7 +6559,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -6478,7 +6577,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -6520,9 +6619,9 @@ } }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } @@ -6746,7 +6845,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -6843,7 +6942,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -6876,7 +6975,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -6885,7 +6984,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -6896,7 +6995,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, @@ -7008,7 +7107,7 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" } } @@ -7065,7 +7164,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, @@ -7089,7 +7188,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -7104,7 +7203,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -7137,7 +7236,7 @@ "dependencies": { "lru-cache": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", + "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", "dev": true, "requires": { @@ -7159,13 +7258,13 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.94", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.94.tgz", - "integrity": "sha512-miQqXALb6eBD3OetCtg3UM5XTLMwHISux0l6mh14iiV5SE+qvftgOCXT9Vvp53fWaCLET4sfA/SmIMYHXkaNmw==" + "version": "1.3.96", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.96.tgz", + "integrity": "sha512-ZUXBUyGLeoJxp4Nt6G/GjBRLnyz8IKQGexZ2ndWaoegThgMGFO1tdDYID5gBV32/1S83osjJHyfzvanE/8HY4Q==" }, "element-closest": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/element-closest/-/element-closest-2.0.2.tgz", + "resolved": "http://registry.npmjs.org/element-closest/-/element-closest-2.0.2.tgz", "integrity": "sha1-cqdAoQdFM4LijfnOXbtajfD5Zuw=" }, "elliptic": { @@ -7360,7 +7459,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -7399,9 +7498,9 @@ } }, "eslint": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.10.0.tgz", - "integrity": "sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ==", + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.11.1.tgz", + "integrity": "sha512-gOKhM8JwlFOc2acbOrkYR05NW8M6DCMSvfcJiBB5NDxRE1gv8kbvxKaC9u69e6ZGEMWXcswA/7eKR229cEIpvg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -7640,16 +7739,18 @@ } }, "eslint-plugin-react": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", - "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.1.tgz", + "integrity": "sha512-1YyXVhp6KSB+xRC1BWzmlA4BH9Wp9jMMBE6AJizxuk+bg/KUJpQGRwsU1/q1pV8rM6oEdLCxunXn7Nfh2BOWBg==", "dev": true, "requires": { "array-includes": "^3.0.3", "doctrine": "^2.1.0", "has": "^1.0.3", "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" + "object.fromentries": "^2.0.0", + "prop-types": "^15.6.2", + "resolve": "^1.9.0" } }, "eslint-plugin-wpcalypso": { @@ -7683,7 +7784,7 @@ }, "espree": { "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "resolved": "http://registry.npmjs.org/espree/-/espree-3.5.4.tgz", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "requires": { "acorn": "^5.5.0", @@ -7729,13 +7830,13 @@ }, "eventemitter2": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "resolved": "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, "events": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", "dev": true }, @@ -7795,7 +7896,7 @@ }, "expand-range": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "requires": { "fill-range": "^2.1.0" @@ -7863,7 +7964,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "requires": { "chardet": "^0.4.0", @@ -8018,7 +8119,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -8038,7 +8139,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -8309,7 +8410,7 @@ "dependencies": { "core-js": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" } } @@ -8443,13 +8544,13 @@ "dependencies": { "colors": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "resolved": "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", "dev": true }, "commander": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.1.0.tgz", "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=", "dev": true } @@ -8457,7 +8558,7 @@ }, "findup-sync": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", "dev": true, "requires": { @@ -8514,7 +8615,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -8529,7 +8630,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -8598,7 +8699,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -8613,7 +8714,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -8672,7 +8773,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -8687,7 +8788,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -9236,7 +9337,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -9304,7 +9405,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -9329,7 +9430,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -9347,7 +9448,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -9392,7 +9493,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, "get-value": { @@ -9416,7 +9517,7 @@ }, "gettext-parser": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", "requires": { "encoding": "^0.1.12", @@ -9480,7 +9581,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -9589,7 +9690,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -9795,7 +9896,7 @@ "dependencies": { "minimist": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", "dev": true } @@ -9811,7 +9912,7 @@ }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -9902,7 +10003,7 @@ }, "grunt-cli": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", "dev": true, "requires": { @@ -9924,7 +10025,7 @@ }, "resolve": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true } @@ -9948,7 +10049,7 @@ }, "chalk": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.2.1.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.2.1.tgz", "integrity": "sha1-dhPhV1FFshOGSD9/SFql/6jL0Qw=", "dev": true, "requires": { @@ -9974,14 +10075,6 @@ "grunt-legacy-log-utils": "~2.0.0", "hooker": "~0.2.3", "lodash": "~4.17.5" - }, - "dependencies": { - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - } } }, "grunt-legacy-log-utils": { @@ -10011,20 +10104,20 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true } } }, "grunt-wp-i18n": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/grunt-wp-i18n/-/grunt-wp-i18n-1.0.2.tgz", - "integrity": "sha512-s7DdR1wRYWvgeQOELL/s8AmWz0scVUq+h0yYVWvLx23kTXOBslvaD35NTvubyM+MO+k29bgND0gDDvS6sHixfg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/grunt-wp-i18n/-/grunt-wp-i18n-1.0.3.tgz", + "integrity": "sha512-CJNbEKeBeOSAPeaJ9B8iCgSwtaG63UR9/uT46a4OsIqnFhOJpeAi138JTlvjfIbnDVoBrzvdrKJe1svveLjUtA==", "dev": true, "requires": { - "grunt": "^1.0.2", - "node-wp-i18n": "^1.0.5" + "grunt": "^1.0.3", + "node-wp-i18n": "^1.2.2" } }, "gud": { @@ -10218,7 +10311,7 @@ }, "hoist-non-react-statics": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=" }, "home-or-tmp": { @@ -10297,7 +10390,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -10389,12 +10482,12 @@ } }, "husky": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.2.0.tgz", - "integrity": "sha512-/ib3+iycykXC0tYIxsyqierikVa9DA2DrT32UEirqNEFVqOj1bFMTgP3jAz8HM7FgC/C8pc/BTUa9MV2GEkZaA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.2.1.tgz", + "integrity": "sha512-4Ylal3HWhnDvIszuiyLoVrSGI7QLg/ogkNCoHE34c+yZYzb9kBZNrlTOsdw92cGi3cJT8pPb6CdVfxFkLnc8Dg==", "dev": true, "requires": { - "cosmiconfig": "^5.0.6", + "cosmiconfig": "^5.0.7", "execa": "^1.0.0", "find-up": "^3.0.0", "get-stdin": "^6.0.0", @@ -10469,9 +10562,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -10517,16 +10610,6 @@ "find-up": "^3.0.0" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", @@ -10788,9 +10871,9 @@ } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, "invariant": { @@ -10819,7 +10902,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -10873,7 +10956,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { "builtin-modules": "^1.0.0" @@ -10894,7 +10977,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -10972,7 +11055,7 @@ }, "is-generator-fn": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=" }, "is-glob": { @@ -11031,7 +11114,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -11595,7 +11678,7 @@ }, "jest-environment-jsdom": { "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", + "resolved": "http://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", "integrity": "sha512-FviwfR+VyT3Datf13+ULjIMO5CSeajlayhhYQwpzgunswoaLIPutdbrnfUHEMyJCwvqQFaVtTmn9+Y8WCt6n1w==", "requires": { "jest-mock": "^22.4.3", @@ -11663,7 +11746,7 @@ }, "jest-get-type": { "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", + "resolved": "http://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" }, "jest-haste-map": { @@ -11754,7 +11837,7 @@ }, "jest-message-util": { "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.3.tgz", + "resolved": "http://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.3.tgz", "integrity": "sha512-iAMeKxhB3Se5xkSjU0NndLLCHtP4n+GtCqV0bISKA5dmOXQfEbdEmYiu2qpnWBDCQdEafNDDU6Q+l6oBMd/+BA==", "requires": { "@babel/code-frame": "^7.0.0-beta.35", @@ -11766,7 +11849,7 @@ }, "jest-mock": { "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-22.4.3.tgz", + "resolved": "http://registry.npmjs.org/jest-mock/-/jest-mock-22.4.3.tgz", "integrity": "sha512-+4R6mH5M1G4NK16CKg9N1DtCaFmuxhcIqF4lQK/Q1CIotqMs/XBemfpDPeVZBFow6iyUNu6EBT9ugdNOTT5o5Q==" }, "jest-regex-util": { @@ -12002,7 +12085,7 @@ }, "jest-util": { "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-22.4.3.tgz", + "resolved": "http://registry.npmjs.org/jest-util/-/jest-util-22.4.3.tgz", "integrity": "sha512-rfDfG8wyC5pDPNdcnAlZgwKnzHvZDu8Td2NJI/jAGKEGxJPYiE4F0ss/gSAkG4778Y23Hvbz+0GMrDJTeo7RjQ==", "requires": { "callsites": "^2.0.0", @@ -12159,12 +12242,12 @@ }, "json5": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -12239,26 +12322,26 @@ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" }, "lerna": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.6.0.tgz", - "integrity": "sha512-iQFAgrgtv18SI5LtQBBca0WVeYvk2r8eYgiEQtcZBT63T5R9RVv+snsviIiOp0z6gD43tcyiWXiLvBdp1IY/Rg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.8.0.tgz", + "integrity": "sha512-OLdf7JSWjpgVecvVLyTRpeKPjTJOcQa366IvaEhorOIxFPZvR1rNIEvi4DMOAaxNINpmCB4nSm769H7H4jNQyw==", "dev": true, "requires": { - "@lerna/add": "^3.6.0", - "@lerna/bootstrap": "^3.6.0", - "@lerna/changed": "^3.6.0", - "@lerna/clean": "^3.6.0", + "@lerna/add": "^3.7.2", + "@lerna/bootstrap": "^3.7.2", + "@lerna/changed": "^3.8.0", + "@lerna/clean": "^3.7.2", "@lerna/cli": "^3.6.0", - "@lerna/create": "^3.6.0", - "@lerna/diff": "^3.6.0", - "@lerna/exec": "^3.6.0", - "@lerna/import": "^3.6.0", - "@lerna/init": "^3.6.0", - "@lerna/link": "^3.6.0", - "@lerna/list": "^3.6.0", - "@lerna/publish": "^3.6.0", - "@lerna/run": "^3.6.0", - "@lerna/version": "^3.6.0", + "@lerna/create": "^3.7.2", + "@lerna/diff": "^3.7.2", + "@lerna/exec": "^3.7.2", + "@lerna/import": "^3.7.2", + "@lerna/init": "^3.7.2", + "@lerna/link": "^3.7.2", + "@lerna/list": "^3.7.2", + "@lerna/publish": "^3.8.0", + "@lerna/run": "^3.7.2", + "@lerna/version": "^3.8.0", "import-local": "^1.0.0", "libnpm": "^2.0.1" } @@ -12331,16 +12414,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -12375,9 +12448,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -12426,16 +12499,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -12465,16 +12528,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -12510,16 +12563,6 @@ "pump": "^3.0.0" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "ssri": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", @@ -12550,16 +12593,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -12589,16 +12622,6 @@ "requires": { "pump": "^3.0.0" } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } } } }, @@ -12654,7 +12677,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -12722,14 +12745,31 @@ "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "dev": true, "requires": { - "big.js": "^3.1.3", + "big.js": "^5.2.2", "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "http://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "locate-path": { @@ -12978,25 +13018,36 @@ }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "dev": true, "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } } }, "mississippi": { @@ -13017,16 +13068,6 @@ "through2": "^2.0.0" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "ssri": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", @@ -13041,6 +13082,12 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true } } }, @@ -13134,7 +13181,7 @@ }, "medium-zoom": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-0.4.0.tgz", + "resolved": "http://registry.npmjs.org/medium-zoom/-/medium-zoom-0.4.0.tgz", "integrity": "sha512-0z7yMfd6I1BTCAa8QaR4cp5AqDkQD571GzhHIbbfefKEssGLSvs+4Xai/itOAncm4FBlF5gUoMQ22yW9/f8Sig==", "dev": true }, @@ -13163,7 +13210,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -13178,7 +13225,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -13285,7 +13332,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -13299,7 +13346,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -13389,7 +13436,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minimist-options": { @@ -13444,6 +13491,18 @@ "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "mixin-deep": { @@ -13485,7 +13544,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -13541,7 +13600,7 @@ }, "multimatch": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", "dev": true, "requires": { @@ -13553,13 +13612,13 @@ }, "mute-stream": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "resolved": "http://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, "nan": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.0.tgz", - "integrity": "sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw==" + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, "nanomatch": { "version": "1.2.13", @@ -13602,12 +13661,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" }, "nearley": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz", - "integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "requires": { + "commander": "^2.19.0", "moo": "^0.4.3", - "nomnom": "~1.6.2", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" @@ -13688,7 +13747,7 @@ "dependencies": { "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true } @@ -13738,7 +13797,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -13753,7 +13812,7 @@ "dependencies": { "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -13776,9 +13835,9 @@ } }, "node-releases": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.1.tgz", - "integrity": "sha512-2UXrBr6gvaebo5TNF84C66qyJJ6r0kxBObgZIDX3D3/mt1ADKiHux3NJPWisq0wxvJJdkjECH+9IIKYViKj71Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.3.tgz", + "integrity": "sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ==", "requires": { "semver": "^5.3.0" } @@ -13824,7 +13883,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -13834,7 +13893,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -13872,7 +13931,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -13890,7 +13949,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -13915,7 +13974,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, @@ -13928,13 +13987,13 @@ } }, "node-wp-i18n": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-wp-i18n/-/node-wp-i18n-1.2.1.tgz", - "integrity": "sha512-Wvl98XA/GBnQFe20iAMwlsXvikVOFTVz//cbRsF8OPQf0NIkJdeWToNYww/dZl52lHtS1KUEIVRyWcol5ibHog==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/node-wp-i18n/-/node-wp-i18n-1.2.2.tgz", + "integrity": "sha512-uRtKibN+PdwED6YzzcdCk4AG7qPt2Cmplpwq0szUz6alz1U/15N1U56EY6kcolGcVrJacW5s70QRB5k8d5k9gg==", "dev": true, "requires": { "bluebird": "^3.4.1", - "gettext-parser": "^2.0.0", + "gettext-parser": "^3.1.0", "glob": "^7.0.5", "lodash": "^4.14.2", "minimist": "^1.2.0", @@ -13943,57 +14002,24 @@ }, "dependencies": { "gettext-parser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-2.1.0.tgz", - "integrity": "sha512-YGmu8DSm7PBnwItT+aOiqejOogqctHFzn+wBKUzjDFQP00psAtn/W2paWQxqE5eA5Ijrqaf7xuTKqyCHpuxnrg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-3.1.0.tgz", + "integrity": "sha512-eVD8RxFMeHg8pjl5zsk7xlEDaKdcYlotLztiMaYGLvI13LMXwWlybLg7rg6eagct79vyGkPGZrMPBsdjsQOnWg==", "dev": true, "requires": { "encoding": "^0.1.12", - "readable-stream": "^2.0.0", + "readable-stream": "^3.0.6", "safe-buffer": "^5.1.2" } }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } } } }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -14279,6 +14305,18 @@ "has": "^1.0.1" } }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", + "has": "^1.0.1" + } + }, "object.getownpropertydescriptors": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", @@ -14364,7 +14402,7 @@ "dependencies": { "ansi-escapes": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "dev": true }, @@ -14376,7 +14414,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14410,13 +14448,13 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "node-fetch": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", "dev": true, "requires": { @@ -14426,7 +14464,7 @@ }, "opn": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "resolved": "http://registry.npmjs.org/opn/-/opn-4.0.2.tgz", "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", "dev": true, "requires": { @@ -14436,7 +14474,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -14500,7 +14538,7 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { @@ -14515,7 +14553,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -14552,7 +14590,7 @@ }, "p-is-promise": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", "dev": true }, @@ -14626,17 +14664,17 @@ } }, "pacote": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.2.3.tgz", - "integrity": "sha512-Y3+yY3nBRAxMlZWvr62XLJxOwCmG9UmkGZkFurWHoCjqF0cZL72cTOCRJTvWw8T4OhJS2RTg13x4oYYriauvEw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.3.0.tgz", + "integrity": "sha512-uy5xghB5wUtmFS+uNhQGhlsIF9rfsfxw6Zsu2VpmSz4/f+8D2+5V1HwjHdSn7W6aQTrxNNmmoUF5qNE10/EVdA==", "dev": true, "requires": { - "bluebird": "^3.5.2", - "cacache": "^11.2.0", + "bluebird": "^3.5.3", + "cacache": "^11.3.2", "figgy-pudding": "^3.5.1", "get-stream": "^4.1.0", "glob": "^7.1.3", - "lru-cache": "^4.1.3", + "lru-cache": "^5.1.1", "make-fetch-happen": "^4.0.1", "minimatch": "^3.0.4", "minipass": "^2.3.5", @@ -14655,30 +14693,30 @@ "safe-buffer": "^5.1.2", "semver": "^5.6.0", "ssri": "^6.0.1", - "tar": "^4.4.6", + "tar": "^4.4.8", "unique-filename": "^1.1.1", "which": "^1.3.1" }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "dev": true, "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, @@ -14691,6 +14729,15 @@ "pump": "^3.0.0" } }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -14709,16 +14756,6 @@ "through2": "^2.0.0" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "ssri": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", @@ -14776,7 +14813,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -14791,7 +14828,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -14808,7 +14845,7 @@ }, "parse-asn1": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", + "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "dev": true, "requires": { @@ -14885,7 +14922,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -14902,7 +14939,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -14980,7 +15017,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { @@ -15108,7 +15145,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -15121,7 +15158,7 @@ "dependencies": { "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -15272,9 +15309,9 @@ } }, "postcss-modules-local-by-default": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.2.tgz", - "integrity": "sha512-qghHvHeydUBQ3EQic5NjYryZ5jzXzAYxHR7lZQlCNmjGpJtINRyX/ELnh/7fxBBmHNkEzNkq2l5cV6trfidYng==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.3.tgz", + "integrity": "sha512-jv4CQ8IQ0+TkaAIP7H4kgu/jQbrjte8xU61SYJAIOby+o3H0MGWX6eN1WXUKHccK6/EEjcAERjyIP8MXzAWAbQ==", "dev": true, "requires": { "css-selector-tokenizer": "^0.7.0", @@ -15360,15 +15397,15 @@ } }, "postcss-reporter": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.0.tgz", - "integrity": "sha512-5xQXm1UPWuFObjbtyQzWvQaupru8yFcFi4HUlm6OPo1o2bUszYASuqRJ7bVArb3svGCdbYtqdMBKrqR1Aoy+tw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", + "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==", "dev": true, "requires": { - "chalk": "^2.0.1", - "lodash": "^4.17.4", - "log-symbols": "^2.0.0", - "postcss": "^7.0.2" + "chalk": "^2.4.1", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "postcss": "^7.0.7" }, "dependencies": { "postcss": { @@ -15612,7 +15649,7 @@ }, "globby": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { @@ -15670,7 +15707,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -15868,9 +15905,9 @@ } }, "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -15886,6 +15923,18 @@ "duplexify": "^3.6.0", "inherits": "^2.0.3", "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "punycode": { @@ -16019,21 +16068,21 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } } }, "react": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react/-/react-16.6.3.tgz", - "integrity": "sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", + "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.11.2" + "scheduler": "^0.12.0" } }, "react-addons-create-fragment": { @@ -16071,11 +16120,12 @@ } }, "react-color": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.14.1.tgz", - "integrity": "sha512-ssv2ArSZdhTbIs29hyfw8JW+s3G4BCx/ILkwCajWZzrcx/2ZQfRpsaLVt38LAPbxe50LLszlmGtRerA14JzzRw==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.17.0.tgz", + "integrity": "sha512-kJfE5tSaFe6GzalXOHksVjqwCPAsTl+nzS9/BWfP7j3EXbQ4IiLAF9sZGNzk3uq7HfofGYgjmcUgh0JP7xAQ0w==", "requires": { - "lodash": "^4.0.1", + "@icons/material": "^0.2.4", + "lodash": ">4.17.4", "material-colors": "^1.2.1", "prop-types": "^15.5.10", "reactcss": "^1.2.0", @@ -16137,7 +16187,7 @@ }, "babylon": { "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", + "resolved": "http://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", "integrity": "sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0=", "dev": true }, @@ -16169,20 +16219,20 @@ } }, "react-dom": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.6.3.tgz", - "integrity": "sha512-8ugJWRCWLGXy+7PmNh8WJz3g1TaTUt1XyoIcFN+x0Zbkoz+KKdUyx1AQLYJdbFXjuF41Nmjn5+j//rxvhFjgSQ==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", + "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.11.2" + "scheduler": "^0.12.0" } }, "react-is": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz", - "integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA==" + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.7.0.tgz", + "integrity": "sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==" }, "react-lifecycles-compat": { "version": "3.0.4", @@ -16307,20 +16357,20 @@ "integrity": "sha512-jZzE+vbYAblPXSPFlir+aL5ljxwB0dJ62O2pR74OS/TUVDTW95msrdszJKLNp4lxzNcoHnCRIzLT6crBgTolGg==" }, "react-test-renderer": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.3.tgz", - "integrity": "sha512-B5bCer+qymrQz/wN03lT0LppbZUDRq6AMfzMKrovzkGzfO81a9T+PWQW6MzkWknbwODQH/qpJno/yFQLX5IWrQ==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.7.0.tgz", + "integrity": "sha512-tFbhSjknSQ6+ttzmuGdv+SjQfmvGcq3PFKyPItohwhhOBmRoTf1We3Mlt3rJtIn85mjPXOkKV+TaKK4irvk9Yg==", "requires": { "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "react-is": "^16.6.3", - "scheduler": "^0.11.2" + "react-is": "^16.7.0", + "scheduler": "^0.12.0" } }, "react-transition-group": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.1.tgz", - "integrity": "sha512-8x/CxUL9SjYFmUdzsBPTgtKeCxt7QArjNSte0wwiLtF/Ix/o1nWNJooNy5o9XbHIKS31pz7J5VF2l41TwlvbHQ==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.2.tgz", + "integrity": "sha512-vwHP++S+f6KL7rg8V1mfs62+MBKtbMeZDR8KiNmD7v98Gs3UPGsDZDahPJH2PVprFW5YHJfh6cbNim3zPndaSQ==", "requires": { "dom-helpers": "^3.3.1", "loose-envify": "^1.4.0", @@ -16477,9 +16527,9 @@ } }, "readable-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.0.tgz", - "integrity": "sha512-vpydAvIJvPODZNagCPuHG87O9JNPtvFEtjHHRVwNVsVVRBqemvPJkc2SYbxJsiZXawJdtZNmkmnsPuE3IgsG0A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16594,7 +16644,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -16614,7 +16664,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -16800,7 +16850,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -16815,7 +16865,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -16938,7 +16988,7 @@ }, "regexpp": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==" }, "regexpu-core": { @@ -16988,7 +17038,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" } } @@ -17149,13 +17199,13 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -17172,6 +17222,15 @@ "locate-path": "^3.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -17209,20 +17268,20 @@ } }, "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "^0.10.0", + "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -17365,7 +17424,7 @@ }, "require-uncached": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "requires": { "caller-path": "^0.1.0", @@ -17568,7 +17627,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -17672,7 +17731,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -17690,7 +17749,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -17853,7 +17912,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "ms": { @@ -17903,7 +17962,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -17912,7 +17971,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -17987,9 +18046,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "scheduler": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.11.3.tgz", - "integrity": "sha512-i9X9VRRVZDd3xZw10NY5Z2cVMbdYg6gqFecfj79USv1CFN+YrJ3gIPRKf1qlY+Sxly4djoKdfx1T+m9dnRB8kQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", + "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -18026,7 +18085,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -18105,9 +18164,9 @@ } }, "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz", + "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==", "dev": true }, "serve-static": { @@ -18161,7 +18220,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -18457,9 +18516,9 @@ } }, "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==" }, "specificity": { "version": "0.4.1", @@ -18499,9 +18558,9 @@ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", + "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -18570,7 +18629,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -18585,7 +18644,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -18601,7 +18660,7 @@ }, "stream-browserify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "dev": true, "requires": { @@ -18611,7 +18670,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -18626,7 +18685,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -18660,7 +18719,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -18675,7 +18734,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -18766,7 +18825,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -18789,7 +18848,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -18815,7 +18874,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -18978,7 +19037,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -18998,7 +19057,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -19102,7 +19161,7 @@ }, "globby": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-8.0.1.tgz", "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { @@ -19351,31 +19410,31 @@ } }, "stylelint-scss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.4.1.tgz", - "integrity": "sha512-ENYTE25wd9ndSkwxMksr8hrXVdWYu+RfDKM1ef2MHEqxk4cU362WQv7mgJK3HZqdCZFxL21sFegQO9Kz2vzwGw==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.4.4.tgz", + "integrity": "sha512-GquwsRegF2gsVRePaUN93cYf9aJDygr03X/QRiwk9O5lOe7QZHlM4Vzrb8JAu+pZ0xodPRpN6W259yA6ApM3WA==", "dev": true, "requires": { "lodash": "^4.17.11", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", - "postcss-selector-parser": "^4.0.0", + "postcss-selector-parser": "^5.0.0", "postcss-value-parser": "^3.3.1" }, "dependencies": { "cssesc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-1.0.1.tgz", - "integrity": "sha512-S2hzrpWvE6G/rW7i7IxJfWBYn27QWfOIncUW++8Rbo1VB5zsJDSVPcnI+Q8z7rhxT6/yZeLOCja4cZnghJrNGA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", "dev": true }, "postcss-selector-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-4.0.0.tgz", - "integrity": "sha512-5h+MvEjnzu1qy6MabjuoPatsGAjjDV9B24e7Cktjl+ClNtjVjmvAXjOFQr1u7RlWULKNGYaYVE4s+DIIQ4bOGA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", "dev": true, "requires": { - "cssesc": "^1.0.1", + "cssesc": "^2.0.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } @@ -19465,7 +19524,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "json-schema-traverse": { @@ -19491,7 +19550,7 @@ }, "tar": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "dev": true, "requires": { @@ -19538,9 +19597,9 @@ } }, "terser": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.11.0.tgz", - "integrity": "sha512-5iLMdhEPIq3zFWskpmbzmKwMQixKmTYwY3Ox9pjtSklBLnHiuQ0GKJLhL1HSYtyffHM3/lDIFBnb82m9D7ewwQ==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.13.1.tgz", + "integrity": "sha512-ogyZye4DFqOtMzT92Y3Nxxw8OvXmL39HOALro4fc+EUYFFF9G/kk0znkvwMz6PPYgBtdKAodh3FPR70eugdaQA==", "dev": true, "requires": { "commander": "~2.17.1", @@ -19548,6 +19607,12 @@ "source-map-support": "~0.5.6" }, "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -19567,9 +19632,9 @@ } }, "terser-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz", + "integrity": "sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw==", "dev": true, "requires": { "cacache": "^11.0.2", @@ -19583,24 +19648,24 @@ }, "dependencies": { "cacache": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.1.tgz", - "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "dev": true, "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "figgy-pudding": "^3.1.0", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.3", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^6.0.0", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, @@ -19634,6 +19699,15 @@ "path-exists": "^3.0.0" } }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -19653,9 +19727,9 @@ } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -19685,16 +19759,6 @@ "find-up": "^3.0.0" } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -19715,6 +19779,12 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true } } }, @@ -19748,7 +19818,7 @@ }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -19763,7 +19833,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -19778,7 +19848,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -19954,7 +20024,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -20039,6 +20109,12 @@ "source-map": "~0.6.1" }, "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "optional": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -20065,11 +20141,6 @@ "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", "dev": true }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=" - }, "underscore.string": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", @@ -20440,9 +20511,9 @@ } }, "validator": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.9.0.tgz", - "integrity": "sha512-hZJcZSWz9poXBlAkjjcsNAdrZ6JbjD3kWlNjq/+vE7RLLS/+8PAj3qVVwrwsOz/WL8jPmZ1hYkRvtlUeZAm4ug==" + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.10.0.tgz", + "integrity": "sha512-DyZyLJlMXM3CGdVaVHE/EDzCagMRoPI3mmGdxxNQbqkGqh56+M3d1i0ZAWd69En8U21DHbPTn12aOdhO+hfm5w==" }, "value-equal": { "version": "0.4.0", @@ -20493,7 +20564,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -20535,7 +20606,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } @@ -20566,9 +20637,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.27.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.27.1.tgz", - "integrity": "sha512-WArHiLvHrlfyRM8i7f+2SFbr/XbQ0bXqTkPF8JpHOzub5482Y3wx7rEO8stuLGOKOgZJcqcisLhD7LrM/+fVMw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.28.2.tgz", + "integrity": "sha512-PK3uVg3/NuNVOjPfYleFI6JF7khO7c2kIlksH7mivQm+QDcwiqV1x6+q89dDeOioh5FNxJHr3LKbDu3oSAhl9g==", "dev": true, "requires": { "@webassemblyjs/ast": "1.7.11", @@ -20698,7 +20769,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -20718,7 +20789,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -20952,13 +21023,13 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -20975,6 +21046,15 @@ "locate-path": "^3.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "import-local": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", @@ -21022,20 +21102,20 @@ } }, "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "^0.10.0", + "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -21189,13 +21269,13 @@ } }, "world-countries": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/world-countries/-/world-countries-2.0.0.tgz", - "integrity": "sha512-f/Atl3VHj/FxFEw5jVkTkKofbbD8z/WF/PCpmv3JPrUR2X/XtuApulLy8QwKcyrurlDDRO0lGPvX+m0GzjxaNQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/world-countries/-/world-countries-2.1.0.tgz", + "integrity": "sha512-g8DRgoH7UJiF5L0xjj+RP/GFH4fOVlD3J5CxkJ+PZYH1PNl0i5JrstBOX53Ub8ObTZ6lCx0V7nIA8BuCvxMoSg==" }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -21212,7 +21292,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -21349,7 +21429,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -21362,7 +21442,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -21370,7 +21450,7 @@ }, "yargs": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "requires": { "cliui": "^4.0.0", diff --git a/plugins/woocommerce-admin/package.json b/plugins/woocommerce-admin/package.json index c0744926f00..4d708d6ec98 100644 --- a/plugins/woocommerce-admin/package.json +++ b/plugins/woocommerce-admin/package.json @@ -45,8 +45,8 @@ "publish:prod": "npm run build:packages && lerna publish from-package" }, "devDependencies": { - "@babel/cli": "7.2.0", - "@babel/core": "7.2.0", + "@babel/cli": "7.2.3", + "@babel/core": "7.2.2", "@babel/plugin-transform-async-to-generator": "7.2.0", "@babel/plugin-transform-react-jsx": "7.2.0", "@babel/runtime-corejs2": "7.2.0", @@ -58,33 +58,33 @@ "@wordpress/jest-preset-default": "2.0.6", "@wordpress/postcss-themes": "1.0.4", "ast-types": "0.11.7", - "autoprefixer": "9.4.2", + "autoprefixer": "9.4.3", "babel-core": "7.0.0-bridge.0", "babel-eslint": "10.0.1", "babel-loader": "8.0.4", "babel-plugin-transform-class-properties": "6.24.1", - "buble": "0.19.6", + "babel-plugin-transform-es2015-template-literals": "6.22.0", "chalk": "2.4.1", "concurrently": "4.1.0", "copy-webpack-plugin": "4.6.0", "cross-env": "5.2.0", - "css-loader": "2.0.0", + "css-loader": "2.1.0", "deasync": "0.1.14", "deep-freeze": "0.0.1", "docsify-cli": "4.3.0", - "eslint": "5.10.0", + "eslint": "5.11.1", "eslint-config-wpcalypso": "4.0.1", "eslint-loader": "2.1.1", "eslint-plugin-jest": "22.1.2", "eslint-plugin-jsx-a11y": "6.1.2", - "eslint-plugin-react": "7.11.1", + "eslint-plugin-react": "7.12.1", "eslint-plugin-wpcalypso": "4.0.2", "extract-text-webpack-plugin": "4.0.0-beta.0", "grunt": "1.0.3", "grunt-checktextdomain": "1.0.1", - "grunt-wp-i18n": "1.0.2", - "husky": "1.2.0", - "lerna": "3.6.0", + "grunt-wp-i18n": "1.0.3", + "husky": "1.2.1", + "lerna": "3.8.0", "node-sass": "4.11.0", "postcss-color-function": "4.0.1", "postcss-loader": "3.0.0", @@ -101,7 +101,7 @@ "style-loader": "0.23.1", "stylelint": "9.9.0", "stylelint-config-wordpress": "13.1.0", - "webpack": "4.27.1", + "webpack": "4.28.2", "webpack-cli": "3.1.2" }, "dependencies": { @@ -119,7 +119,7 @@ "@wordpress/viewport": "^2.0.7", "browser-filesaver": "^1.1.1", "classnames": "^2.2.5", - "core-js": "2.6.0", + "core-js": "2.6.1", "d3-array": "^2.0.0", "d3-axis": "^1.0.12", "d3-format": "^1.3.2", diff --git a/plugins/woocommerce-admin/packages/components/CHANGELOG.md b/plugins/woocommerce-admin/packages/components/CHANGELOG.md index fba739a637b..5774db71a64 100644 --- a/plugins/woocommerce-admin/packages/components/CHANGELOG.md +++ b/plugins/woocommerce-admin/packages/components/CHANGELOG.md @@ -1,3 +1,10 @@ +# 1.4.0 ( unreleased ) +- Add download log ip address autocompleter to search component +- Add order number autocompleter to search component +- Add order number, username, and IP address filters to the downloads report. +- Added `interactive` prop for `d3chart/legend` to signal if legend items are clickable or not. +- Fix for undefined ref in `d3chart/legend` + # 1.3.0 - Update `` to use header keys to denote which columns are shown diff --git a/plugins/woocommerce-admin/packages/components/package.json b/plugins/woocommerce-admin/packages/components/package.json index 5d4d95d3434..4f1a39ac57c 100644 --- a/plugins/woocommerce-admin/packages/components/package.json +++ b/plugins/woocommerce-admin/packages/components/package.json @@ -35,7 +35,7 @@ "@wordpress/keycodes": "2.0.2", "@wordpress/viewport": "^2.0.7", "classnames": "^2.2.5", - "core-js": "2.6.0", + "core-js": "2.6.1", "d3-array": "^2.0.0", "d3-axis": "^1.0.12", "d3-format": "^1.3.2", diff --git a/plugins/woocommerce-admin/packages/components/src/calendar/date-picker.js b/plugins/woocommerce-admin/packages/components/src/calendar/date-picker.js new file mode 100644 index 00000000000..4781d3e49f5 --- /dev/null +++ b/plugins/woocommerce-admin/packages/components/src/calendar/date-picker.js @@ -0,0 +1,141 @@ +/** @format */ +/** + * External dependencies + */ +import 'core-js/fn/object/assign'; +import 'core-js/fn/array/from'; +import { __, sprintf } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { Dropdown, DatePicker as WpDatePicker } from '@wordpress/components'; +import { partial } from 'lodash'; +import { TAB } from '@wordpress/keycodes'; +import moment from 'moment'; + +/** + * Internal dependencies + */ +import DateInput from './input'; +import { toMoment } from '@woocommerce/date'; +import { H, Section } from '../section'; +import PropTypes from 'prop-types'; + +class DatePicker extends Component { + constructor( props ) { + super( props ); + + this.onDateChange = this.onDateChange.bind( this ); + this.onInputChange = this.onInputChange.bind( this ); + } + + handleKeyDown( isOpen, onToggle, { keyCode } ) { + if ( TAB === keyCode && isOpen ) { + onToggle(); + } + } + + handleFocus( isOpen, onToggle ) { + if ( ! isOpen ) { + onToggle(); + } + } + + onDateChange( onToggle, dateString ) { + const { onUpdate, dateFormat } = this.props; + const date = moment( dateString ); + onUpdate( { + date, + text: dateString ? date.format( dateFormat ) : '', + error: null, + } ); + onToggle(); + } + + onInputChange( event ) { + const value = event.target.value; + const { dateFormat } = this.props; + const date = toMoment( dateFormat, value ); + const error = date ? null : __( 'Invalid date', 'wc-admin' ); + + this.props.onUpdate( { + date, + text: value, + error: value.length > 0 ? error : null, + } ); + } + + render() { + const { date, text, dateFormat, error } = this.props; + // @TODO: make upstream Gutenberg change to invalidate certain days. + // const isOutsideRange = getOutsideRange( invalidDays ); + return ( + ( + + ) } + renderContent={ ( { onToggle } ) => ( +
+ + { __( 'select a date', 'wc-admin' ) } + +
+ +
+
+ ) } + /> + ); + } +} + +DatePicker.propTypes = { + /** + * A moment date object representing the selected date. `null` for no selection. + */ + date: PropTypes.object, + /** + * The date in human-readable format. Displayed in the text input. + */ + text: PropTypes.string, + /** + * A string error message, shown to the user. + */ + error: PropTypes.string, + /** + * (Coming Soon) Optionally invalidate certain days. `past`, `future`, `none`, or function are accepted. + * A function will be passed to react-dates' `isOutsideRange` prop + */ + invalidDays: PropTypes.oneOfType( [ + PropTypes.oneOf( [ 'past', 'future', 'none' ] ), + PropTypes.func, + ] ), + /** + * A function called upon selection of a date or input change. + */ + onUpdate: PropTypes.func.isRequired, + /** + * The date format in moment.js-style tokens. + */ + dateFormat: PropTypes.string.isRequired, +}; + +export default DatePicker; diff --git a/plugins/woocommerce-admin/packages/components/src/calendar/index.js b/plugins/woocommerce-admin/packages/components/src/calendar/date-range.js similarity index 89% rename from plugins/woocommerce-admin/packages/components/src/calendar/index.js rename to plugins/woocommerce-admin/packages/components/src/calendar/date-range.js index 1711ffff7a8..9d8deb3b7e4 100644 --- a/plugins/woocommerce-admin/packages/components/src/calendar/index.js +++ b/plugins/woocommerce-admin/packages/components/src/calendar/date-range.js @@ -7,11 +7,7 @@ import 'core-js/fn/array/from'; import { __, sprintf } from '@wordpress/i18n'; import classnames from 'classnames'; import { Component } from '@wordpress/element'; -import { - DayPickerRangeController, - isInclusivelyAfterDay, - isInclusivelyBeforeDay, -} from 'react-dates'; +import { DayPickerRangeController } from 'react-dates'; import moment from 'moment'; import { partial } from 'lodash'; import PropTypes from 'prop-types'; @@ -27,6 +23,7 @@ import { validateDateInputForRange } from '@woocommerce/date'; */ import DateInput from './input'; import phrases from './phrases'; +import { getOutsideRange } from './utils'; /** * This is wrapper for a [react-dates](https://github.com/airbnb/react-dates) powered calendar. @@ -38,7 +35,6 @@ class DateRange extends Component { this.onDatesChange = this.onDatesChange.bind( this ); this.onFocusChange = this.onFocusChange.bind( this ); this.onInputChange = this.onInputChange.bind( this ); - this.getOutsideRange = this.getOutsideRange.bind( this ); } onDatesChange( { startDate, endDate } ) { @@ -76,22 +72,6 @@ class DateRange extends Component { } ); } - getOutsideRange() { - const { invalidDays } = this.props; - if ( 'string' === typeof invalidDays ) { - switch ( invalidDays ) { - case 'past': - return day => isInclusivelyBeforeDay( day, moment() ); - case 'future': - return day => isInclusivelyAfterDay( day, moment() ); - case 'none': - default: - return undefined; - } - } - return 'function' === typeof invalidDays ? invalidDays : undefined; - } - setTnitialVisibleMonth( isDoubleCalendar, before ) { return () => { const visibleDate = before || moment(); @@ -114,8 +94,9 @@ class DateRange extends Component { shortDateFormat, isViewportMobile, isViewportSmall, + invalidDays, } = this.props; - const isOutsideRange = this.getOutsideRange(); + const isOutsideRange = getOutsideRange( invalidDays ); const isDoubleCalendar = isViewportMobile && ! isViewportSmall; return (
{ - function onUpdate( { after, afterText, before, beforeText } ) { - setState( { after, afterText, before, beforeText } ); + after: null, + afterText: '', + before: null, + beforeText: '', + afterError: null, + beforeError: null, + focusedInput: 'startDate', +} )( ( { after, afterText, before, beforeText, afterError, beforeError, focusedInput, setState } ) => { + function onRangeUpdate( update ) { + setState( update ); } - + + function onDatePickerUpdate( { date, text, error } ) { + setState( { + after: date, + afterText: text, + afterError: error, + } ); + } + return ( - +
+ Date Range Picker +
+ +
+ + Date Picker +
+ +
+
) } ); ``` diff --git a/plugins/woocommerce-admin/packages/components/src/calendar/input.js b/plugins/woocommerce-admin/packages/components/src/calendar/input.js index 0c88e299077..02844dd4c33 100644 --- a/plugins/woocommerce-admin/packages/components/src/calendar/input.js +++ b/plugins/woocommerce-admin/packages/components/src/calendar/input.js @@ -4,10 +4,20 @@ */ import { Dashicon, Popover } from '@wordpress/components'; import classnames from 'classnames'; -import { uniqueId } from 'lodash'; +import { uniqueId, noop } from 'lodash'; import PropTypes from 'prop-types'; -const DateInput = ( { value, onChange, dateFormat, label, describedBy, error } ) => { +const DateInput = ( { + value, + onChange, + dateFormat, + label, + describedBy, + error, + onFocus, + onKeyDown, + errorPosition, +} ) => { const classes = classnames( 'woocommerce-calendar__input', { 'is-empty': value.length === 0, 'is-error': error, @@ -24,12 +34,14 @@ const DateInput = ( { value, onChange, dateFormat, label, describedBy, error } ) id={ id } aria-describedby={ `${ id }-message` } placeholder={ dateFormat.toLowerCase() } + onFocus={ onFocus } + onKeyDown={ onKeyDown } /> { error && ( { error } @@ -49,6 +61,15 @@ DateInput.propTypes = { label: PropTypes.string.isRequired, describedBy: PropTypes.string.isRequired, error: PropTypes.string, + errorPosition: PropTypes.string, + onFocus: PropTypes.func, + onKeyDown: PropTypes.func, +}; + +DateInput.defaultProps = { + onFocus: () => {}, + errorPosition: 'bottom center', + onKeyDown: noop, }; export default DateInput; diff --git a/plugins/woocommerce-admin/packages/components/src/calendar/style.scss b/plugins/woocommerce-admin/packages/components/src/calendar/style.scss index 8f85f829cfa..84d055bac1e 100644 --- a/plugins/woocommerce-admin/packages/components/src/calendar/style.scss +++ b/plugins/woocommerce-admin/packages/components/src/calendar/style.scss @@ -60,6 +60,22 @@ outline: 2px solid #bfe7f3; } } + + // Make exceptions for wp Core DatePicker. + &.is-core-datepicker { + .components-datetime__date { + padding-left: 0; + } + + .CalendarDay__default { + background-color: transparent; + } + + .CalendarDay__selected { + background: $woocommerce-700; + border: none; + } + } } .woocommerce-calendar__inputs { @@ -143,32 +159,50 @@ } .woocommerce-filters-date__content { - .woocommerce-calendar__input-error { - display: none; - - .components-popover__content { - background-color: $core-grey-dark-400; - color: $white; - padding: 0.5em; - border: none; - } - - &.components-popover { - .components-popover__content { - min-width: 100px; - width: 100px; - text-align: center; - } - - &:not(.no-arrow):not(.is-mobile).is-bottom::before { - border-bottom-color: $core-grey-dark-400; - z-index: 1; - top: -6px; - } - } - } - &.is-mobile .woocommerce-calendar__input-error .components-popover__content { height: initial; } } + +.woocommerce-calendar__input-error { + display: none; + + .components-popover__content { + background-color: $core-grey-dark-400; + color: $white; + padding: 0.5em; + border: none; + } + + &.components-popover { + .components-popover__content { + min-width: 100px; + width: 100px; + text-align: center; + } + + &:not(.no-arrow):not(.is-mobile).is-bottom::before { + border-bottom-color: $core-grey-dark-400; + z-index: 1; + top: -6px; + } + + &:not(.no-arrow):not(.is-mobile).is-top::after { + border-top-color: $core-grey-dark-400; + z-index: 1; + top: 0; + } + } +} + +.woocommerce-calendar__date-picker-title { + @include font-size( 12 ); + font-weight: 100; + text-transform: uppercase; + text-align: center; + color: $core-grey-dark-300; + width: 100%; + margin: 0; + padding: 1em; + background-color: $white; +} diff --git a/plugins/woocommerce-admin/packages/components/src/calendar/utils.js b/plugins/woocommerce-admin/packages/components/src/calendar/utils.js new file mode 100644 index 00000000000..206d110e573 --- /dev/null +++ b/plugins/woocommerce-admin/packages/components/src/calendar/utils.js @@ -0,0 +1,20 @@ +/** @format */ +/** + * External dependencies + */ +import moment from 'moment'; + +export function getOutsideRange( invalidDays ) { + if ( 'string' === typeof invalidDays ) { + switch ( invalidDays ) { + case 'past': + return day => moment().isAfter( day, 'day' ); + case 'future': + return day => moment().isBefore( day, 'day' ); + case 'none': + default: + return undefined; + } + } + return 'function' === typeof invalidDays ? invalidDays : undefined; +} diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/chart.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/chart.js index 2749c106e82..b7144a65a43 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/chart.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/chart.js @@ -127,6 +127,7 @@ class D3Chart extends Component { adjWidth, colorScheme, dateSpaces: getDateSpaces( data, uniqueDates, adjWidth, xLineScale ), + interval, line: getLine( xLineScale, yScale ), lineData, margin, diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/legend.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/legend.js index c51111c326e..9ba9c053354 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/legend.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/legend.js @@ -35,6 +35,9 @@ class D3Legend extends Component { } updateListScroll() { + if ( ! this.listRef ) { + return; + } const list = this.listRef.current; const scrolledToEnd = list.scrollHeight - list.scrollTop <= list.offsetHeight; this.setState( { @@ -48,6 +51,7 @@ class D3Legend extends Component { data, handleLegendHover, handleLegendToggle, + interactive, legendDirection, legendValueFormat, totalLabel, @@ -92,7 +96,7 @@ class D3Legend extends Component {