Show compared keys in chart legends even if their values are 0 (https://github.com/woocommerce/woocommerce-admin/pull/1754)
* Show compared keys in chart legends * Fix JS error if filters is missing * Add docs
This commit is contained in:
parent
1a395fd11f
commit
a7e3cf78a0
|
@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';
|
||||||
import { Component } from '@wordpress/element';
|
import { Component } from '@wordpress/element';
|
||||||
import { compose } from '@wordpress/compose';
|
import { compose } from '@wordpress/compose';
|
||||||
import { format as formatDate } from '@wordpress/date';
|
import { format as formatDate } from '@wordpress/date';
|
||||||
|
import { get } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +28,7 @@ import { Chart } from '@woocommerce/components';
|
||||||
import { getReportChartData, getTooltipValueFormat } from 'wc-api/reports/utils';
|
import { getReportChartData, getTooltipValueFormat } from 'wc-api/reports/utils';
|
||||||
import ReportError from 'analytics/components/report-error';
|
import ReportError from 'analytics/components/report-error';
|
||||||
import withSelect from 'wc-api/with-select';
|
import withSelect from 'wc-api/with-select';
|
||||||
import { getChartMode } from './utils';
|
import { getChartMode, getSelectedFilter } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders the chart in reports.
|
* Component that renders the chart in reports.
|
||||||
|
@ -92,6 +93,7 @@ export class ReportChart extends Component {
|
||||||
renderChart( mode, isRequesting, chartData ) {
|
renderChart( mode, isRequesting, chartData ) {
|
||||||
const {
|
const {
|
||||||
emptySearchResults,
|
emptySearchResults,
|
||||||
|
filterParam,
|
||||||
interactiveLegend,
|
interactiveLegend,
|
||||||
itemsLabel,
|
itemsLabel,
|
||||||
legendPosition,
|
legendPosition,
|
||||||
|
@ -113,6 +115,7 @@ export class ReportChart extends Component {
|
||||||
data={ chartData }
|
data={ chartData }
|
||||||
dateParser={ '%Y-%m-%dT%H:%M:%S' }
|
dateParser={ '%Y-%m-%dT%H:%M:%S' }
|
||||||
emptyMessage={ emptyMessage }
|
emptyMessage={ emptyMessage }
|
||||||
|
filterParam={ filterParam }
|
||||||
interactiveLegend={ interactiveLegend }
|
interactiveLegend={ interactiveLegend }
|
||||||
interval={ currentInterval }
|
interval={ currentInterval }
|
||||||
isRequesting={ isRequesting }
|
isRequesting={ isRequesting }
|
||||||
|
@ -238,25 +241,30 @@ export default compose(
|
||||||
withSelect( ( select, props ) => {
|
withSelect( ( select, props ) => {
|
||||||
const { endpoint, filters, isRequesting, limitProperty, query } = props;
|
const { endpoint, filters, isRequesting, limitProperty, query } = props;
|
||||||
const limitBy = limitProperty || endpoint;
|
const limitBy = limitProperty || endpoint;
|
||||||
const chartMode = props.mode || getChartMode( filters, query ) || 'time-comparison';
|
const selectedFilter = getSelectedFilter( filters, query );
|
||||||
|
const filterParam = get( selectedFilter, [ 'settings', 'param' ] );
|
||||||
|
const chartMode = props.mode || getChartMode( selectedFilter, query ) || 'time-comparison';
|
||||||
|
|
||||||
|
const newProps = {
|
||||||
|
mode: chartMode,
|
||||||
|
filterParam,
|
||||||
|
};
|
||||||
|
|
||||||
if ( isRequesting ) {
|
if ( isRequesting ) {
|
||||||
return {
|
return newProps;
|
||||||
mode: chartMode,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( query.search && ! ( query[ limitBy ] && query[ limitBy ].length ) ) {
|
if ( query.search && ! ( query[ limitBy ] && query[ limitBy ].length ) ) {
|
||||||
return {
|
return {
|
||||||
|
...newProps,
|
||||||
emptySearchResults: true,
|
emptySearchResults: true,
|
||||||
mode: chartMode,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( 'item-comparison' === chartMode ) {
|
if ( 'item-comparison' === chartMode ) {
|
||||||
const primaryData = getReportChartData( endpoint, 'primary', query, select, limitBy );
|
const primaryData = getReportChartData( endpoint, 'primary', query, select, limitBy );
|
||||||
return {
|
return {
|
||||||
mode: chartMode,
|
...newProps,
|
||||||
primaryData,
|
primaryData,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -264,7 +272,7 @@ export default compose(
|
||||||
const primaryData = getReportChartData( endpoint, 'primary', query, select, limitBy );
|
const primaryData = getReportChartData( endpoint, 'primary', query, select, limitBy );
|
||||||
const secondaryData = getReportChartData( endpoint, 'secondary', query, select, limitBy );
|
const secondaryData = getReportChartData( endpoint, 'secondary', query, select, limitBy );
|
||||||
return {
|
return {
|
||||||
mode: chartMode,
|
...newProps,
|
||||||
primaryData,
|
primaryData,
|
||||||
secondaryData,
|
secondaryData,
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { shallow } from 'enzyme';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { ReportChart } from '../';
|
import { ReportChart } from '../';
|
||||||
import { getChartMode } from '../utils';
|
import { getChartMode, getSelectedFilter } from '../utils';
|
||||||
|
|
||||||
jest.mock( '@woocommerce/components', () => ( {
|
jest.mock( '@woocommerce/components', () => ( {
|
||||||
...require.requireActual( '@woocommerce/components' ),
|
...require.requireActual( '@woocommerce/components' ),
|
||||||
|
@ -63,7 +63,8 @@ describe( 'ReportChart', () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const query = { filter: 'lorem-ipsum', filter2: 'ipsum-lorem' };
|
const query = { filter: 'lorem-ipsum', filter2: 'ipsum-lorem' };
|
||||||
const mode = getChartMode( filters, query );
|
const selectedFilter = getSelectedFilter( filters, query );
|
||||||
|
const mode = getChartMode( selectedFilter, query );
|
||||||
expect( mode ).toEqual( 'item-comparison' );
|
expect( mode ).toEqual( 'item-comparison' );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -13,32 +13,30 @@ import { flattenFilters } from '@woocommerce/navigation';
|
||||||
export const DEFAULT_FILTER = 'all';
|
export const DEFAULT_FILTER = 'all';
|
||||||
|
|
||||||
export function getSelectedFilter( filters, query, selectedFilterArgs = {} ) {
|
export function getSelectedFilter( filters, query, selectedFilterArgs = {} ) {
|
||||||
if ( filters.length === 0 ) {
|
if ( ! filters || filters.length === 0 ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterConfig = filters.pop();
|
const clonedFilters = filters.slice( 0 );
|
||||||
|
const filterConfig = clonedFilters.pop();
|
||||||
|
|
||||||
if ( filterConfig.showFilters( query, selectedFilterArgs ) ) {
|
if ( filterConfig.showFilters( query, selectedFilterArgs ) ) {
|
||||||
const allFilters = flattenFilters( filterConfig.filters );
|
const allFilters = flattenFilters( filterConfig.filters );
|
||||||
const value = query[ filterConfig.param ] || DEFAULT_FILTER;
|
const value = query[ filterConfig.param ] || DEFAULT_FILTER;
|
||||||
const selectedFilter = find( allFilters, { value } );
|
return find( allFilters, { value } );
|
||||||
|
}
|
||||||
|
|
||||||
|
return getSelectedFilter( clonedFilters, query, selectedFilterArgs );
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChartMode( selectedFilter, query ) {
|
||||||
|
if ( selectedFilter && query ) {
|
||||||
const selectedFilterParam = get( selectedFilter, [ 'settings', 'param' ] );
|
const selectedFilterParam = get( selectedFilter, [ 'settings', 'param' ] );
|
||||||
|
|
||||||
if ( ! selectedFilterParam || Object.keys( query ).includes( selectedFilterParam ) ) {
|
if ( ! selectedFilterParam || Object.keys( query ).includes( selectedFilterParam ) ) {
|
||||||
return selectedFilter;
|
return get( selectedFilter, [ 'chartMode' ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSelectedFilter( filters, query, selectedFilterArgs );
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
export function getChartMode( filters, query, selectedFilterArgs ) {
|
|
||||||
if ( ! filters ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const clonedFilters = filters.slice( 0 );
|
|
||||||
const selectedFilter = getSelectedFilter( clonedFilters, query, selectedFilterArgs );
|
|
||||||
|
|
||||||
return get( selectedFilter, [ 'chartMode' ] );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# (unreleased)
|
# (unreleased)
|
||||||
- Chart legend component now uses withInstanceId HOC so the ids used in several HTML elements are unique.
|
- Chart legend component now uses withInstanceId HOC so the ids used in several HTML elements are unique.
|
||||||
|
- Chart component: new prop `filterParam` used to detect selected items in the current query. If there are, they will be displayed in the chart even if their values are 0.
|
||||||
|
|
||||||
# 1.6.0
|
# 1.6.0
|
||||||
- Chart component: new props `emptyMessage` and `baseValue`. When an empty message is provided, it will be displayed on top of the chart if there are no values different than `baseValue`.
|
- Chart component: new props `emptyMessage` and `baseValue`. When an empty message is provided, it will be displayed on top of the chart if there are no values different than `baseValue`.
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { withViewportMatch } from '@wordpress/viewport';
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
*/
|
*/
|
||||||
import { updateQueryString } from '@woocommerce/navigation';
|
import { getIdsFromQuery, updateQueryString } from '@woocommerce/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -74,7 +74,9 @@ function getOrderedKeys( props, previousOrderedKeys = [] ) {
|
||||||
if ( 'item-comparison' === props.mode ) {
|
if ( 'item-comparison' === props.mode ) {
|
||||||
updatedKeys.sort( ( a, b ) => b.total - a.total );
|
updatedKeys.sort( ( a, b ) => b.total - a.total );
|
||||||
if ( isEmpty( previousOrderedKeys ) ) {
|
if ( isEmpty( previousOrderedKeys ) ) {
|
||||||
return updatedKeys.filter( key => key.total > 0 ).map( ( key, index ) => {
|
const selectedIds = props.filterParam ? getIdsFromQuery( props.query[ props.filterParam ] ) : [];
|
||||||
|
const filteredKeys = updatedKeys.filter( key => key.total > 0 || selectedIds.includes( parseInt( key.key, 10 ) ) );
|
||||||
|
return filteredKeys.map( ( key, index ) => {
|
||||||
return {
|
return {
|
||||||
...key,
|
...key,
|
||||||
visible: index < selectionLimit || key.visible,
|
visible: index < selectionLimit || key.visible,
|
||||||
|
@ -443,6 +445,12 @@ Chart.propTypes = {
|
||||||
* nothing will be displayed.
|
* nothing will be displayed.
|
||||||
*/
|
*/
|
||||||
emptyMessage: PropTypes.string,
|
emptyMessage: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Name of the param used to filter items. If specified, it will be used, in combination
|
||||||
|
* with query, to detect which elements are being used by the current filter and must be
|
||||||
|
* displayed even if their value is 0.
|
||||||
|
*/
|
||||||
|
filterParam: PropTypes.string,
|
||||||
/**
|
/**
|
||||||
* Label describing the legend items.
|
* Label describing the legend items.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue