Merge pull request woocommerce/woocommerce-admin#419 from woocommerce/add/coupons-autocompleter-plumbing

Add Coupons autocompleter and relevant configs
This commit is contained in:
Paul Sealock 2018-09-21 11:57:56 +12:00 committed by GitHub
commit 679ce51bd1
20 changed files with 218 additions and 66 deletions

View File

@ -0,0 +1,33 @@
/** @format */
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { getRequestByIdString } from 'lib/async-requests';
import { NAMESPACE } from 'store/constants';
export const filters = [
{ label: __( 'All Coupons', 'wc-admin' ), value: 'all' },
{
label: __( 'Comparison', 'wc-admin' ),
value: 'compare',
settings: {
type: 'coupons',
param: 'coupon',
getLabels: getRequestByIdString( NAMESPACE + 'coupons', coupon => ( {
id: coupon.id,
label: coupon.code,
} ) ),
labels: {
title: __( 'Compare Coupon Codes', 'wc-admin' ),
update: __( 'Compare', 'wc-admin' ),
},
},
},
{ label: __( 'Top Coupons by Discounted Orders', 'wc-admin' ), value: 'top_orders' },
{ label: __( 'Top Coupons by Gross Discounted', 'wc-admin' ), value: 'top_discount' },
];

View File

@ -0,0 +1,23 @@
/** @format */
/**
* External dependencies
*/
import { Component, Fragment } from '@wordpress/element';
/**
* Internal dependencies
*/
import { filters } from './config';
import { ReportFilters } from '@woocommerce/components';
export default class extends Component {
render() {
const { query, path } = this.props;
return (
<Fragment>
<ReportFilters query={ query } path={ path } filters={ filters } />
</Fragment>
);
}
}

View File

@ -16,6 +16,7 @@ import Header from 'layout/header';
import OrdersReport from './orders'; import OrdersReport from './orders';
import ProductsReport from './products'; import ProductsReport from './products';
import RevenueReport from './revenue'; import RevenueReport from './revenue';
import CouponsReport from './coupons';
import useFilters from 'components/higher-order/use-filters'; import useFilters from 'components/higher-order/use-filters';
const REPORTS_FILTER = 'woocommerce-reports-list'; const REPORTS_FILTER = 'woocommerce-reports-list';
@ -37,6 +38,11 @@ const getReports = () => {
title: __( 'Orders', 'wc-admin' ), title: __( 'Orders', 'wc-admin' ),
component: OrdersReport, component: OrdersReport,
}, },
{
report: 'coupons',
title: __( 'Coupons', 'wc-admin' ),
component: CouponsReport,
},
] ); ] );
return reports; return reports;

View File

@ -7,7 +7,8 @@ import { __ } from '@wordpress/i18n';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { getProductLabelsById } from 'analytics/report/products/config'; import { getRequestByIdString } from 'lib/async-requests';
import { NAMESPACE } from 'store/constants';
export const filters = [ export const filters = [
{ label: __( 'All Orders', 'wc-admin' ), value: 'all' }, { label: __( 'All Orders', 'wc-admin' ), value: 'all' },
@ -69,7 +70,10 @@ export const advancedFilterConfig = {
input: { input: {
component: 'Search', component: 'Search',
type: 'products', type: 'products',
getLabels: getProductLabelsById, getLabels: getRequestByIdString( NAMESPACE + 'products', product => ( {
id: product.id,
label: product.name,
} ) ),
}, },
}, },
code: { code: {
@ -88,7 +92,11 @@ export const advancedFilterConfig = {
], ],
input: { input: {
component: 'Search', component: 'Search',
type: 'products', // For now. "coupons" autocompleter required type: 'coupons',
getLabels: getRequestByIdString( NAMESPACE + 'coupons', coupon => ( {
id: coupon.id,
label: coupon.code,
} ) ),
}, },
}, },
customer: { customer: {

View File

@ -14,7 +14,6 @@ import { partial } from 'lodash';
*/ */
import { Card, ReportFilters } from '@woocommerce/components'; import { Card, ReportFilters } from '@woocommerce/components';
import { filters, advancedFilterConfig } from './config'; import { filters, advancedFilterConfig } from './config';
import './style.scss';
class OrdersReport extends Component { class OrdersReport extends Component {
constructor( props ) { constructor( props ) {

View File

@ -3,38 +3,13 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { getIdsFromQuery, stringifyQuery } from 'lib/nav-utils'; import { getRequestByIdString } from 'lib/async-requests';
import { NAMESPACE } from 'store/constants'; import { NAMESPACE } from 'store/constants';
export function getProductLabelsById( queryString = '' ) {
const idList = getIdsFromQuery( queryString );
if ( idList.length < 1 ) {
return Promise.resolve( [] );
}
const payload = stringifyQuery( {
include: idList.join( ',' ),
per_page: idList.length,
} );
return apiFetch( { path: `${ NAMESPACE }products${ payload }` } );
}
export function getCategoryLabelsById( queryString = '' ) {
const idList = getIdsFromQuery( queryString );
if ( idList.length < 1 ) {
return Promise.resolve( [] );
}
const payload = stringifyQuery( {
include: idList.join( ',' ),
per_page: idList.length,
} );
return apiFetch( { path: `${ NAMESPACE }products/categories${ payload }` } );
}
export const filters = [ export const filters = [
{ label: __( 'All Products', 'wc-admin' ), value: 'all' }, { label: __( 'All Products', 'wc-admin' ), value: 'all' },
{ {
@ -54,7 +29,10 @@ export const filters = [
settings: { settings: {
type: 'products', type: 'products',
param: 'product', param: 'product',
getLabels: getProductLabelsById, getLabels: getRequestByIdString( NAMESPACE + 'products', product => ( {
id: product.id,
label: product.name,
} ) ),
labels: { labels: {
helpText: __( 'Select at least two products to compare', 'wc-admin' ), helpText: __( 'Select at least two products to compare', 'wc-admin' ),
placeholder: __( 'Search for products to compare', 'wc-admin' ), placeholder: __( 'Search for products to compare', 'wc-admin' ),
@ -69,7 +47,10 @@ export const filters = [
settings: { settings: {
type: 'product_cats', type: 'product_cats',
param: 'product_cat', param: 'product_cat',
getLabels: getCategoryLabelsById, getLabels: getRequestByIdString( NAMESPACE + 'products/categories', category => ( {
id: category.id,
label: category.name,
} ) ),
labels: { labels: {
helpText: __( 'Select at least two product categories to compare', 'wc-admin' ), helpText: __( 'Select at least two product categories to compare', 'wc-admin' ),
placeholder: __( 'Search for product categories to compare', 'wc-admin' ), placeholder: __( 'Search for product categories to compare', 'wc-admin' ),

View File

@ -14,7 +14,6 @@ import { formatCurrency, getCurrencyFormatDecimal } from 'lib/currency';
import { numberFormat } from 'lib/number'; import { numberFormat } from 'lib/number';
import { getAdminLink, onQueryChange } from 'lib/nav-utils'; import { getAdminLink, onQueryChange } from 'lib/nav-utils';
import { ReportFilters, TableCard } from '@woocommerce/components'; import { ReportFilters, TableCard } from '@woocommerce/components';
import './style.scss';
import products from './__mocks__/data'; import products from './__mocks__/data';

View File

@ -28,8 +28,7 @@ class SearchFilter extends Component {
} }
} }
updateLabels( data ) { updateLabels( selected ) {
const selected = data.map( p => ( { id: p.id, label: p.name } ) );
this.setState( { selected } ); this.setState( { selected } );
} }

View File

@ -57,8 +57,7 @@ class CompareFilter extends Component {
return getNewPath( { [ param ]: undefined }, path, query ); return getNewPath( { [ param ]: undefined }, path, query );
} }
updateLabels( data ) { updateLabels( selected ) {
const selected = data.map( p => ( { id: p.id, label: p.name } ) );
this.setState( { selected } ); this.setState( { selected } );
} }

View File

@ -0,0 +1,59 @@
/** @format */
/**
* External dependencies
*/
import apiFetch from '@wordpress/api-fetch';
/**
* Internal dependencies
*/
import { computeSuggestionMatch } from './utils';
import { stringifyQuery } from 'lib/nav-utils';
import { NAMESPACE } from 'store/constants';
/**
* A coupon completer.
* See https://github.com/WordPress/gutenberg/tree/master/packages/components/src/autocomplete#the-completer-interface
*
* @type {Completer}
*/
export default {
name: 'coupons',
className: 'woocommerce-search__coupon-result',
options( search ) {
let payload = '';
if ( search ) {
const query = {
search: encodeURIComponent( search ),
per_page: 10,
};
payload = stringifyQuery( query );
}
return apiFetch( { path: `${ NAMESPACE }coupons${ payload }` } );
},
isDebounced: true,
getOptionKeywords( coupon ) {
return [ coupon.code ];
},
getOptionLabel( coupon, query ) {
const match = computeSuggestionMatch( coupon.code, query ) || {};
return [
<span key="name" className="woocommerce-search__result-name" aria-label={ coupon.code }>
{ match.suggestionBeforeMatch }
<strong className="components-form-token-field__suggestion-match">
{ match.suggestionMatch }
</strong>
{ match.suggestionAfterMatch }
</span>,
];
},
// This is slightly different than gutenberg/Autocomplete, we don't support different methods
// of replace/insertion, so we can just return the value.
getOptionCompletion( coupon ) {
const value = {
id: coupon.id,
label: coupon.code,
};
return value;
},
};

View File

@ -4,3 +4,4 @@
*/ */
export { default as product } from './product'; export { default as product } from './product';
export { default as productCategory } from './product-cat'; export { default as productCategory } from './product-cat';
export { default as coupons } from './coupons';

View File

@ -9,6 +9,7 @@ import apiFetch from '@wordpress/api-fetch';
*/ */
import { computeSuggestionMatch } from './utils'; import { computeSuggestionMatch } from './utils';
import { stringifyQuery } from 'lib/nav-utils'; import { stringifyQuery } from 'lib/nav-utils';
import { NAMESPACE } from 'store/constants';
/** /**
* A product categories completer. * A product categories completer.
@ -29,7 +30,7 @@ export default {
}; };
payload = stringifyQuery( query ); payload = stringifyQuery( query );
} }
return apiFetch( { path: '/wc/v3/products/categories' + payload } ); return apiFetch( { path: `${ NAMESPACE }products/categories${ payload }` } );
}, },
isDebounced: true, isDebounced: true,
getOptionKeywords( cat ) { getOptionKeywords( cat ) {

View File

@ -10,6 +10,7 @@ import apiFetch from '@wordpress/api-fetch';
import { computeSuggestionMatch } from './utils'; import { computeSuggestionMatch } from './utils';
import ProductImage from 'components/product-image'; import ProductImage from 'components/product-image';
import { stringifyQuery } from 'lib/nav-utils'; import { stringifyQuery } from 'lib/nav-utils';
import { NAMESPACE } from 'store/constants';
/** /**
* A products completer. * A products completer.
@ -30,7 +31,7 @@ export default {
}; };
payload = stringifyQuery( query ); payload = stringifyQuery( query );
} }
return apiFetch( { path: '/wc/v3/products' + payload } ); return apiFetch( { path: `${ NAMESPACE }products${ payload }` } );
}, },
isDebounced: true, isDebounced: true,
getOptionKeywords( product ) { getOptionKeywords( product ) {

View File

@ -12,7 +12,7 @@ import PropTypes from 'prop-types';
* Internal dependencies * Internal dependencies
*/ */
import Autocomplete from './autocomplete'; import Autocomplete from './autocomplete';
import { product, productCategory } from './autocompleters'; import { product, productCategory, coupons } from './autocompleters';
import Tag from 'components/tag'; import Tag from 'components/tag';
import './style.scss'; import './style.scss';
@ -64,6 +64,8 @@ class Search extends Component {
return product; return product;
case 'product_cats': case 'product_cats':
return productCategory; return productCategory;
case 'coupons':
return coupons;
default: default:
return {}; return {};
} }
@ -125,7 +127,8 @@ Search.propTypes = {
/** /**
* The object type to be used in searching. * The object type to be used in searching.
*/ */
type: PropTypes.oneOf( [ 'products', 'product_cats', 'orders', 'customers' ] ).isRequired, type: PropTypes.oneOf( [ 'products', 'product_cats', 'orders', 'customers', 'coupons' ] )
.isRequired,
/** /**
* A placeholder for the search input. * A placeholder for the search input.
*/ */

View File

@ -0,0 +1,33 @@
/** @format */
/**
* External dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { identity } from 'lodash';
/**
* Internal dependencies
*/
import { getIdsFromQuery, stringifyQuery } from 'lib/nav-utils';
/**
* Get a function that accepts ids as they are found in url parameter and
* returns a promise with an optional method applied to results
*
* @param {string} path - api path
* @param {Function} [handleData] - function applied to each iteration of data
* @returns {Function} - a function of ids returning a promise
*/
export function getRequestByIdString( path, handleData = identity ) {
return function( queryString = '' ) {
const idList = getIdsFromQuery( queryString );
if ( idList.length < 1 ) {
return Promise.resolve( [] );
}
const payload = stringifyQuery( {
include: idList.join( ',' ),
per_page: idList.length,
} );
return apiFetch( { path: path + payload } ).then( data => data.map( handleData ) );
};
}

View File

@ -4,6 +4,7 @@
*/ */
import history from 'lib/history'; import history from 'lib/history';
import { parse, stringify } from 'qs'; import { parse, stringify } from 'qs';
import { uniq } from 'lodash';
/** /**
* Returns a string with the site's wp-admin URL appended. JS version of `admin_url`. * Returns a string with the site's wp-admin URL appended. JS version of `admin_url`.
@ -35,10 +36,12 @@ export const stringifyQuery = query => ( query ? '?' + stringify( query ) : '' )
* @return {Array} List of IDs converted to numbers. * @return {Array} List of IDs converted to numbers.
*/ */
export function getIdsFromQuery( queryString = '' ) { export function getIdsFromQuery( queryString = '' ) {
return queryString return uniq(
queryString
.split( ',' ) .split( ',' )
.map( id => parseInt( id, 10 ) ) .map( id => parseInt( id, 10 ) )
.filter( Boolean ); .filter( Boolean )
);
} }
/** /**

View File

@ -96,6 +96,12 @@ function wc_admin_register_pages() {
'parent' => '/analytics', 'parent' => '/analytics',
'path' => '/analytics/orders', 'path' => '/analytics/orders',
) ); ) );
wc_admin_register_page( array(
'title' => __( 'Coupons', 'wc-admin' ),
'parent' => '/analytics',
'path' => '/analytics/coupons',
) );
} }
add_action( 'admin_menu', 'wc_admin_register_pages' ); add_action( 'admin_menu', 'wc_admin_register_pages' );

View File

@ -2531,7 +2531,7 @@
}, },
"babel-plugin-syntax-class-properties": { "babel-plugin-syntax-class-properties": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
"dev": true "dev": true
}, },
@ -2943,7 +2943,7 @@
}, },
"browserify-aes": { "browserify-aes": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -2980,7 +2980,7 @@
}, },
"browserify-rsa": { "browserify-rsa": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -3042,7 +3042,7 @@
}, },
"buffer": { "buffer": {
"version": "4.9.1", "version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -3751,7 +3751,7 @@
}, },
"create-hash": { "create-hash": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -3764,7 +3764,7 @@
}, },
"create-hmac": { "create-hmac": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4406,7 +4406,7 @@
}, },
"diffie-hellman": { "diffie-hellman": {
"version": "5.0.3", "version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -5525,7 +5525,7 @@
}, },
"external-editor": { "external-editor": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -7170,7 +7170,7 @@
}, },
"http-errors": { "http-errors": {
"version": "1.6.3", "version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -7735,7 +7735,7 @@
}, },
"is-obj": { "is-obj": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true "dev": true
}, },
@ -9748,7 +9748,7 @@
}, },
"jsonfile": { "jsonfile": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -11358,7 +11358,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
}, },
@ -11561,7 +11561,7 @@
}, },
"parse-asn1": { "parse-asn1": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -12491,7 +12491,7 @@
}, },
"public-encrypt": { "public-encrypt": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "http://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
"integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -12642,7 +12642,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@ -13615,7 +13615,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@ -13650,7 +13650,7 @@
}, },
"os-locale": { "os-locale": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -13931,7 +13931,7 @@
}, },
"sha.js": { "sha.js": {
"version": "2.4.11", "version": "2.4.11",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -15354,7 +15354,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }