2018-11-26 14:01:20 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2020-05-29 02:32:37 +00:00
|
|
|
import { CheckboxControl, Button } from '@wordpress/components';
|
2018-12-05 01:44:32 +00:00
|
|
|
import { applyFilters } from '@wordpress/hooks';
|
2020-06-10 16:46:46 +00:00
|
|
|
import { Fragment, useRef, useState } from '@wordpress/element';
|
2018-11-26 14:01:20 +00:00
|
|
|
import { compose } from '@wordpress/compose';
|
2019-04-30 09:43:55 +00:00
|
|
|
import { focus } from '@wordpress/dom';
|
2018-12-13 19:24:54 +00:00
|
|
|
import { withDispatch } from '@wordpress/data';
|
2020-06-10 16:46:46 +00:00
|
|
|
import { get, noop, partial, uniq } from 'lodash';
|
2019-10-08 22:02:26 +00:00
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import classnames from 'classnames';
|
2018-11-26 14:01:20 +00:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* WooCommerce dependencies
|
|
|
|
*/
|
2019-10-08 22:02:26 +00:00
|
|
|
import { CompareButton, Search, TableCard } from '@woocommerce/components';
|
|
|
|
import DownloadIcon from './download-icon';
|
|
|
|
import {
|
|
|
|
getIdsFromQuery,
|
|
|
|
getSearchWords,
|
|
|
|
onQueryChange,
|
|
|
|
updateQueryString,
|
|
|
|
} from '@woocommerce/navigation';
|
|
|
|
import {
|
|
|
|
downloadCSVFile,
|
|
|
|
generateCSVDataFromTable,
|
|
|
|
generateCSVFileName,
|
|
|
|
} from '@woocommerce/csv-export';
|
2020-06-10 16:46:46 +00:00
|
|
|
import { SETTINGS_STORE_NAME, useUserPreferences } from '@woocommerce/data';
|
2018-11-26 14:01:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import ReportError from 'analytics/components/report-error';
|
2019-01-30 07:22:10 +00:00
|
|
|
import { getReportChartData, getReportTableData } from 'wc-api/reports/utils';
|
2019-02-05 12:00:37 +00:00
|
|
|
import { QUERY_DEFAULTS } from 'wc-api/constants';
|
2018-12-05 17:10:54 +00:00
|
|
|
import withSelect from 'wc-api/with-select';
|
2018-12-12 14:25:36 +00:00
|
|
|
import { extendTableData } from './utils';
|
2019-07-02 10:05:37 +00:00
|
|
|
import { recordEvent } from 'lib/tracks';
|
2019-04-30 09:43:55 +00:00
|
|
|
import './style.scss';
|
|
|
|
|
2018-12-05 01:44:32 +00:00
|
|
|
const TABLE_FILTER = 'woocommerce_admin_report_table';
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const ReportTable = ( props ) => {
|
|
|
|
const {
|
|
|
|
getHeadersContent,
|
|
|
|
getRowsContent,
|
|
|
|
getSummary,
|
|
|
|
isRequesting,
|
|
|
|
primaryData,
|
|
|
|
tableData,
|
|
|
|
endpoint,
|
|
|
|
// These props are not used in the render function, but are destructured
|
|
|
|
// so they are not included in the `tableProps` variable.
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
itemIdField,
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
tableQuery,
|
|
|
|
compareBy,
|
|
|
|
searchBy,
|
|
|
|
labels = {},
|
|
|
|
...tableProps
|
|
|
|
} = props;
|
|
|
|
|
|
|
|
// Pull these props out separately because they need to be included in tableProps.
|
|
|
|
const { query, columnPrefsKey } = props;
|
|
|
|
|
|
|
|
const { items, query: reportQuery } = tableData;
|
|
|
|
|
|
|
|
const initialSelectedRows = query.filter
|
|
|
|
? getIdsFromQuery( query[ compareBy ] )
|
|
|
|
: [];
|
|
|
|
const [ selectedRows, setSelectedRows ] = useState( initialSelectedRows );
|
|
|
|
const scrollPointRef = useRef( null );
|
|
|
|
|
|
|
|
const { updateUserPreferences, ...userData } = useUserPreferences();
|
|
|
|
|
|
|
|
// Bail early if we've encountered an error.
|
|
|
|
const isError = tableData.isError || primaryData.isError;
|
|
|
|
|
|
|
|
if ( isError ) {
|
|
|
|
return <ReportError isError />;
|
2019-10-08 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
let userPrefColumns = [];
|
|
|
|
if ( columnPrefsKey ) {
|
|
|
|
userPrefColumns =
|
|
|
|
userData && userData[ columnPrefsKey ]
|
|
|
|
? userData[ columnPrefsKey ]
|
|
|
|
: userPrefColumns;
|
2018-12-22 11:46:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onColumnsChange = ( shownColumns, toggledColumn ) => {
|
2020-02-14 02:23:21 +00:00
|
|
|
const columns = getHeadersContent().map( ( header ) => header.key );
|
|
|
|
const hiddenColumns = columns.filter(
|
|
|
|
( column ) => ! shownColumns.includes( column )
|
|
|
|
);
|
2018-12-13 19:24:54 +00:00
|
|
|
|
|
|
|
if ( columnPrefsKey ) {
|
|
|
|
const userDataFields = {
|
2018-12-22 02:27:30 +00:00
|
|
|
[ columnPrefsKey ]: hiddenColumns,
|
2018-12-13 19:24:54 +00:00
|
|
|
};
|
2020-06-10 16:46:46 +00:00
|
|
|
updateUserPreferences( userDataFields );
|
2018-12-13 19:24:54 +00:00
|
|
|
}
|
2019-07-09 19:55:51 +00:00
|
|
|
|
|
|
|
if ( toggledColumn ) {
|
|
|
|
const eventProps = {
|
|
|
|
report: endpoint,
|
|
|
|
column: toggledColumn,
|
|
|
|
status: shownColumns.includes( toggledColumn ) ? 'on' : 'off',
|
|
|
|
};
|
|
|
|
|
|
|
|
recordEvent( 'analytics_table_header_toggle', eventProps );
|
|
|
|
}
|
2018-12-22 11:46:10 +00:00
|
|
|
}
|
2018-12-13 19:24:54 +00:00
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onPageChange = ( newPage, source ) => {
|
|
|
|
scrollPointRef.current.scrollIntoView();
|
|
|
|
const tableElement = scrollPointRef.current.nextSibling.querySelector(
|
2019-04-30 09:43:55 +00:00
|
|
|
'.woocommerce-table__table'
|
|
|
|
);
|
|
|
|
const focusableElements = focus.focusable.find( tableElement );
|
|
|
|
|
|
|
|
if ( focusableElements.length ) {
|
|
|
|
focusableElements[ 0 ].focus();
|
|
|
|
}
|
2019-07-11 17:53:47 +00:00
|
|
|
|
|
|
|
if ( source ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
if ( source === 'goto' ) {
|
|
|
|
recordEvent( 'analytics_table_go_to_page', {
|
|
|
|
report: endpoint,
|
|
|
|
page: newPage,
|
|
|
|
} );
|
2019-07-11 17:53:47 +00:00
|
|
|
} else {
|
2020-02-14 02:23:21 +00:00
|
|
|
recordEvent( 'analytics_table_page_click', {
|
|
|
|
report: endpoint,
|
|
|
|
direction: source,
|
|
|
|
} );
|
2019-07-11 17:53:47 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-30 09:43:55 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const trackTableSearch = () => {
|
2019-07-10 14:37:02 +00:00
|
|
|
// @todo: decide if this should only fire for new tokens (not any/all changes).
|
|
|
|
recordEvent( 'analytics_table_filter', { report: endpoint } );
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onSort = ( key, direction ) => {
|
2019-07-09 20:38:53 +00:00
|
|
|
onQueryChange( 'sort' )( key, direction );
|
|
|
|
|
|
|
|
const eventProps = {
|
|
|
|
report: endpoint,
|
|
|
|
column: key,
|
|
|
|
direction,
|
|
|
|
};
|
|
|
|
|
|
|
|
recordEvent( 'analytics_table_sort', eventProps );
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const filterShownHeaders = ( headers, hiddenKeys ) => {
|
2019-08-16 19:05:43 +00:00
|
|
|
// If no user preferences, set visibilty based on column default.
|
|
|
|
if ( ! hiddenKeys ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
return headers.map( ( header ) => ( {
|
2019-08-16 19:05:43 +00:00
|
|
|
...header,
|
|
|
|
visible: header.required || ! header.hiddenByDefault,
|
|
|
|
} ) );
|
2018-12-13 19:24:54 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 19:05:43 +00:00
|
|
|
// Set visibilty based on user preferences.
|
2020-02-14 02:23:21 +00:00
|
|
|
return headers.map( ( header ) => ( {
|
2019-08-16 19:05:43 +00:00
|
|
|
...header,
|
|
|
|
visible: header.required || ! hiddenKeys.includes( header.key ),
|
|
|
|
} ) );
|
2018-12-22 11:46:10 +00:00
|
|
|
}
|
2018-12-13 19:24:54 +00:00
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onClickDownload = () => {
|
2019-10-08 22:02:26 +00:00
|
|
|
const {
|
|
|
|
initiateReportExport,
|
|
|
|
title,
|
2020-06-10 16:46:46 +00:00
|
|
|
} = props;
|
2019-10-08 22:02:26 +00:00
|
|
|
const params = Object.assign( {}, query );
|
|
|
|
const { data, totalResults } = items;
|
|
|
|
let downloadType = 'browser';
|
|
|
|
|
|
|
|
// Delete unnecessary items from filename.
|
|
|
|
delete params.extended_info;
|
|
|
|
if ( params.search ) {
|
|
|
|
delete params[ searchBy ];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( data && data.length === totalResults ) {
|
|
|
|
downloadCSVFile(
|
|
|
|
generateCSVFileName( title, params ),
|
2020-02-14 02:23:21 +00:00
|
|
|
generateCSVDataFromTable(
|
|
|
|
getHeadersContent(),
|
|
|
|
getRowsContent( data )
|
|
|
|
)
|
2019-10-08 22:02:26 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
downloadType = 'email';
|
|
|
|
initiateReportExport( endpoint, title, reportQuery );
|
|
|
|
}
|
|
|
|
|
|
|
|
recordEvent( 'analytics_table_download', {
|
|
|
|
report: endpoint,
|
|
|
|
rows: totalResults,
|
|
|
|
downloadType,
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onCompare = () => {
|
|
|
|
const { compareParam } = props;
|
2019-10-08 22:02:26 +00:00
|
|
|
if ( compareBy ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
onQueryChange( 'compare' )(
|
|
|
|
compareBy,
|
|
|
|
compareParam,
|
|
|
|
selectedRows.join( ',' )
|
|
|
|
);
|
2019-10-08 22:02:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const onSearchChange = ( values ) => {
|
|
|
|
const { baseSearchQuery, compareParam } = props;
|
2019-10-08 22:02:26 +00:00
|
|
|
// A comma is used as a separator between search terms, so we want to escape
|
|
|
|
// any comma they contain.
|
2020-06-10 16:46:46 +00:00
|
|
|
const searchTerms = values.map( ( v ) => v.label.replace( ',', '%2C' ) );
|
|
|
|
if ( searchTerms.length ) {
|
2019-10-08 22:02:26 +00:00
|
|
|
updateQueryString( {
|
|
|
|
filter: undefined,
|
|
|
|
[ compareParam ]: undefined,
|
|
|
|
[ searchBy ]: undefined,
|
|
|
|
...baseSearchQuery,
|
2020-06-10 16:46:46 +00:00
|
|
|
search: uniq( searchTerms ).join( ',' ),
|
2019-10-08 22:02:26 +00:00
|
|
|
} );
|
|
|
|
} else {
|
|
|
|
updateQueryString( {
|
|
|
|
search: undefined,
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
trackTableSearch();
|
2019-10-08 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const selectAllRows = ( checked ) => {
|
|
|
|
const { ids } = props;
|
|
|
|
setSelectedRows( checked ? ids : [] );
|
2019-10-08 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const selectRow = ( i, checked ) => {
|
|
|
|
const { ids } = props;
|
2019-12-13 17:35:29 +00:00
|
|
|
if ( checked ) {
|
2020-06-10 16:46:46 +00:00
|
|
|
setSelectedRows( uniq( [ ids[ i ], ...selectedRows ] ) );
|
2019-10-08 22:02:26 +00:00
|
|
|
} else {
|
2020-06-10 16:46:46 +00:00
|
|
|
const index = selectedRows.indexOf( ids[ i ] );
|
|
|
|
setSelectedRows( [
|
|
|
|
...selectedRows.slice( 0, index ),
|
|
|
|
...selectedRows.slice( index + 1 ),
|
|
|
|
] );
|
2019-10-08 22:02:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const getCheckbox = ( i ) => {
|
|
|
|
const { ids = [] } = props;
|
2020-02-14 02:23:21 +00:00
|
|
|
const isChecked = selectedRows.indexOf( ids[ i ] ) !== -1;
|
2019-10-08 22:02:26 +00:00
|
|
|
return {
|
2020-02-14 02:23:21 +00:00
|
|
|
display: (
|
|
|
|
<CheckboxControl
|
2020-06-10 16:46:46 +00:00
|
|
|
onChange={ partial( selectRow, i ) }
|
2020-02-14 02:23:21 +00:00
|
|
|
checked={ isChecked }
|
|
|
|
/>
|
|
|
|
),
|
2019-10-08 22:02:26 +00:00
|
|
|
value: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const getAllCheckbox = () => {
|
|
|
|
const { ids = [] } = props;
|
2019-10-08 22:02:26 +00:00
|
|
|
const hasData = ids.length > 0;
|
|
|
|
const isAllChecked = hasData && ids.length === selectedRows.length;
|
|
|
|
return {
|
|
|
|
cellClassName: 'is-checkbox-column',
|
|
|
|
key: 'compare',
|
|
|
|
label: (
|
2019-12-13 17:35:29 +00:00
|
|
|
<CheckboxControl
|
2020-06-10 16:46:46 +00:00
|
|
|
onChange={ selectAllRows }
|
2019-10-08 22:02:26 +00:00
|
|
|
aria-label={ __( 'Select All' ) }
|
|
|
|
checked={ isAllChecked }
|
|
|
|
disabled={ ! hasData }
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
required: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
const isLoading =
|
|
|
|
isRequesting || tableData.isRequesting || primaryData.isRequesting;
|
|
|
|
const totals = get( primaryData, [ 'data', 'totals' ], {} );
|
|
|
|
const totalResults = items.totalResults;
|
|
|
|
const downloadable = totalResults > 0;
|
|
|
|
// Search words are in the query string, not the table query.
|
|
|
|
const searchWords = getSearchWords( query );
|
|
|
|
const searchedLabels = searchWords.map( ( v ) => ( {
|
|
|
|
key: v,
|
|
|
|
label: v,
|
|
|
|
} ) );
|
2018-11-26 14:01:20 +00:00
|
|
|
|
2020-06-10 16:46:46 +00:00
|
|
|
/**
|
|
|
|
* Filter report table.
|
|
|
|
*
|
|
|
|
* Enables manipulation of data used to create a report table.
|
|
|
|
*
|
|
|
|
* @param {Object} reportTableData - data used to create the table.
|
|
|
|
* @param {string} reportTableData.endpoint - table api endpoint.
|
|
|
|
* @param {Array} reportTableData.headers - table headers data.
|
|
|
|
* @param {Array} reportTableData.rows - table rows data.
|
|
|
|
* @param {Object} reportTableData.totals - total aggregates for request.
|
|
|
|
* @param {Array} reportTableData.summary - summary numbers data.
|
|
|
|
* @param {Object} reportTableData.items - response from api requerst.
|
|
|
|
*/
|
|
|
|
const filteredTableProps = applyFilters( TABLE_FILTER, {
|
|
|
|
endpoint,
|
|
|
|
headers: getHeadersContent(),
|
|
|
|
rows: getRowsContent( items.data ),
|
|
|
|
totals,
|
|
|
|
summary: getSummary ? getSummary( totals, totalResults ) : null,
|
|
|
|
items,
|
|
|
|
} );
|
|
|
|
let { headers, rows } = filteredTableProps;
|
|
|
|
const { summary } = filteredTableProps;
|
|
|
|
|
|
|
|
// Add in selection for comparisons.
|
|
|
|
if ( compareBy ) {
|
|
|
|
rows = rows.map( ( row, i ) => {
|
|
|
|
return [ getCheckbox( i ), ...row ];
|
Merge final `version/1.0` branch with `master` (https://github.com/woocommerce/woocommerce-admin/pull/3848)
* Try: Moving Customers to main Woo Menu (https://github.com/woocommerce/woocommerce-admin/pull/3632)
* Only add onboarding settings on wc-admin pages when task list should be shown. (https://github.com/woocommerce/woocommerce-admin/pull/3722)
* Use cron for unsnoozing admin notes (https://github.com/woocommerce/woocommerce-admin/pull/3662)
* Use wp-cron for admin note snoozing.
* Remove "unsnooze" scheduled action.
* Use correct version.
* Avoid using deprecated method for unscheduling actions.
* Onboarding: Fix toggle tracking events (https://github.com/woocommerce/woocommerce-admin/pull/3645)
* Fix errant wcadmin prefix on event name
* Track the onboarding toggle on the option in case enable_onboarding isn't used
* Move toggle actions to separate function
* Move onboarding actions
* Move onboarding filters
* Move help tab updates to add_toggle_actions
* Only run onboarding actions when enabled
* Onboarding: Add tracks events when profiler steps are completed (https://github.com/woocommerce/woocommerce-admin/pull/3726)
* Add tracks for store profiler step completion
* Record event when profiler is completed
* Ensure continue setup loads the onboarding profiler (https://github.com/woocommerce/woocommerce-admin/pull/3646)
* 'All that include' option removed when input field is empty (https://github.com/woocommerce/woocommerce-admin/pull/3700)
* 'All that include' option removed when input field is empty
Added a control to check that when the input field 'Search by customer name' is empty, the 'All that include' option is not appearing.
* Const name improved
The constant name hasValues was changed to optionsHaveValues (more descriptive)
* Fix select text alignment (https://github.com/woocommerce/woocommerce-admin/pull/3723)
* Stock panel indicator - cache and use lookup tables. (https://github.com/woocommerce/woocommerce-admin/pull/3729)
* Stock panel indicator - cache and use lookup tables.
* Revise query, clear transient on product update.
* Fix error, ht Josh.
* Checklist: Remove sideloaded images to reduce build size, take 2 (https://github.com/woocommerce/woocommerce-admin/pull/3731)
* Remove homepage template images.
* Use other-small on all industries, adjust text color.
* Remove background dim and opacity set to 0
* Fix/3631 (https://github.com/woocommerce/woocommerce-admin/pull/3730)
* Added CBD as an industry type
CBD was added as an industry type in API
* Industries options modified
Modified the industries options. Now we are able to choose if we will use an input or not in the option.
* API control changed for industries.
API control changed for industries. Now it accepts the data type we need.
* Added input in Industries list for the option "Other"
Added an input for the option "Other" in the industries list
* Added suggested changes in review comments.
* Added data preparation for recordEvent
* Changed variable to snake_case
The variable "industriesWithDetail" was changed to "industries_with_detail" (snake_case)
* Onboarding: Create homepage without redirect (https://github.com/woocommerce/woocommerce-admin/pull/3727)
* Add link to edit homepage instead of redirect
* Add busy state to homepage creation button
* Publish homepage on create via API
* Update homepage notice to show on first post update
* Update homepage creation notice per design
* Record event on customize homepage
* Set homepage to frontpage on creation
* Add deactivation note for feature plugin (https://github.com/woocommerce/woocommerce-admin/pull/3687)
* Add version deactivation note
* Add the note to deactivate if the version is older than the current WC version
* Deactivate wc admin feature plugin on action click
* Add notes version hooks
* change the Package class namespace to exclude from standalone autoloader
* add use statement for FeaturePlugin
* add note explaining namespace
* use wc-admin-deactivate-plugin note name
* Rename file and class to WC_Admin_Notes_Deactivate_Plugin
Co-authored-by: Ron Rennick <ron@ronandandrea.com>
Co-authored-by: Paul Sealock <psealock@gmail.com>
* Add Travis tests on GH for release branch (https://github.com/woocommerce/woocommerce-admin/pull/3751)
* Add Travis tests on GH for release branch
* fix linter errors
* ActivityPanels.php -> use public static functions
* Remove free text Search option when no query exists (https://github.com/woocommerce/woocommerce-admin/pull/3755)
* Revert changes in woocommerce/woocommerce-admin#3700
* Don't add free text search if no query exists
* Add tests for Search without query
* Add test for showing free text search option
* Fix image sideloading for store industries. (https://github.com/woocommerce/woocommerce-admin/pull/3743)
* Fix image sideloading for store industries.
Data format changed in https://github.com/woocommerce/woocommerce-admin/pull/3730
* Fix industry image sideload in cases where the count is less than requested.
* Be backwards compatible with the old industry data format.
* Added event props to identify stores with WCS and Jetpack installed (https://github.com/woocommerce/woocommerce-admin/pull/3750)
* Added event props to identify stores with WCS and Jetpack installed
Also, added Jeckpack connected status
* Improved variable name
* Simplified method
Simplified method. "intersection" check was removed
* Tests errors repeared
The method "clear_low_out_of_stock_count_transient" now is static.
* OBW: fix sideloading image test error (https://github.com/woocommerce/woocommerce-admin/pull/3762)
* Release 0.26.0 changes (https://github.com/woocommerce/woocommerce-admin/pull/3753)
* add deactivation hook to Package.php (https://github.com/woocommerce/woocommerce-admin/pull/3770)
* Add active version functions (https://github.com/woocommerce/woocommerce-admin/pull/3772)
* add active version functions to Package.php
Co-authored-by: Joshua T Flowers <joshuatf@gmail.com>
* 0.26.1 changes (https://github.com/woocommerce/woocommerce-admin/pull/3773)
* Customers Report: fix missing report param in search (https://github.com/woocommerce/woocommerce-admin/pull/3778)
* Product titles include encoded entities (https://github.com/woocommerce/woocommerce-admin/pull/3765)
* Stripped HTML from product titles and decoded before displaying them
Stripped html from product titles and entities are decoded before displaying them
* Stripped HTML from product titles and decoded in Stock report
Stripped html from product titles and entities are decoded before displaying them. Now in Stock report
* Added support for HTML tags and encoded entities on product titles
Added support for HTML tags and encoded entities on filtered product list, dropdown menus and tag names.
Also, strip_tags() function was replaced with wp_strip_all_tags() instead.
* strip_tags() function was replaced with wp_strip_all_tags() instead.
* Added control for a variable
Added control for "item->data" before applying wp_strip_all_tags method.
* pre-commit changes
* Test text corrected
* Enable taxes on automatic tax setup (https://github.com/woocommerce/woocommerce-admin/pull/3795)
* Update Country Labeling to Match Core (https://github.com/woocommerce/woocommerce-admin/pull/3790)
* Updated country labeling
Country labeling on Customer Report was updated
* Updated country labeling in other files
* remove .jitm-card notice padding (https://github.com/woocommerce/woocommerce-admin/pull/3814)
* OBW Connect: Fix requesting state (https://github.com/woocommerce/woocommerce-admin/pull/3786)
* OBW Connect: Fix requesting state
* pass down setIsPending
* setIspending propType
* defaultProps
* test
* Revert "test"
This reverts commit e921092b19401931cc1aec8ee84fa53c53b67f36.
* better comparison for redirect
* Fixes Taxes Report search bug and adds initial documentation. (https://github.com/woocommerce/woocommerce-admin/pull/3816)
* Initial Taxes Report documentation.
* Fix taxes endpoint search parameter.
* OBW: Fix retry plugin install button disappearing (https://github.com/woocommerce/woocommerce-admin/pull/3787)
* OBW: Fix retry plugin install btn disappearing
* try suggestion
* Revert "try suggestion"
This reverts commit 5b9386957a501ac3e729e5f16b0ee71c9d792859.
* Fix special character escaping in search. (https://github.com/woocommerce/woocommerce-admin/pull/3826)
* Properly prepare/escape special characters in Product search.
* Properly prepare/escape special characters in Coupon search.
* Properly prepare/escape special characters in Tax code search.
* Fix tracking on migrated options (https://github.com/woocommerce/woocommerce-admin/pull/3828)
* Don't track onboarding toggle if migrating options
* Prevent WC_Tracks from recording event post types not yet registered
* Activity Panels: Remove W Panel (https://github.com/woocommerce/woocommerce-admin/pull/3827)
* Remove W Notif Panel.
* Add back in trapping logic, and hide on non-embed pages.
* add npm run test:zip command (https://github.com/woocommerce/woocommerce-admin/pull/3823)
* add npm run test:zip command
* 1.0.0 release changes🎉 (https://github.com/woocommerce/woocommerce-admin/pull/3831)
* 1.0.0 release changes🎉
* changelog
* 0.26.1 changelog
* Add Report Extension Example: Add default props to ReportFilters (https://github.com/woocommerce/woocommerce-admin/pull/3830)
* ReportFilters component: Add sane defaults
* styles
* add required column
* add left join to sku ordering (https://github.com/woocommerce/woocommerce-admin/pull/3845)
* Deal with lint errors, and improperly merged files
* regenerate package-lock.json
* attempting to resolve package lock conflict.
Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com>
Co-authored-by: Joshua T Flowers <joshuatf@gmail.com>
Co-authored-by: Ron Rennick <ron@ronandandrea.com>
Co-authored-by: Fernando <ultimoround@gmail.com>
Co-authored-by: edmundcwm <edmundcwm@gmail.com>
Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-03-10 02:47:39 +00:00
|
|
|
} );
|
2020-06-10 16:46:46 +00:00
|
|
|
headers = [ getAllCheckbox(), ...headers ];
|
2018-11-26 14:01:20 +00:00
|
|
|
}
|
2020-06-10 16:46:46 +00:00
|
|
|
|
|
|
|
// Hide any headers based on user prefs, if loaded.
|
|
|
|
const filteredHeaders = filterShownHeaders( headers, userPrefColumns );
|
|
|
|
const className = classnames( 'woocommerce-report-table', {
|
|
|
|
'has-compare': !! compareBy,
|
|
|
|
'has-search': !! searchBy,
|
|
|
|
} );
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<div
|
|
|
|
className="woocommerce-report-table__scroll-point"
|
|
|
|
ref={ scrollPointRef }
|
|
|
|
aria-hidden
|
|
|
|
/>
|
|
|
|
<TableCard
|
|
|
|
className={ className }
|
|
|
|
actions={ [
|
|
|
|
compareBy && (
|
|
|
|
<CompareButton
|
|
|
|
key="compare"
|
|
|
|
className="woocommerce-table__compare"
|
|
|
|
count={ selectedRows.length }
|
|
|
|
helpText={
|
|
|
|
labels.helpText ||
|
|
|
|
__(
|
|
|
|
'Check at least two items below to compare',
|
|
|
|
'woocommerce-admin'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
onClick={ onCompare }
|
|
|
|
disabled={ ! downloadable }
|
|
|
|
>
|
|
|
|
{ labels.compareButton ||
|
|
|
|
__( 'Compare', 'woocommerce-admin' ) }
|
|
|
|
</CompareButton>
|
|
|
|
),
|
|
|
|
searchBy && (
|
|
|
|
<Search
|
|
|
|
allowFreeTextSearch={ true }
|
|
|
|
inlineTags
|
|
|
|
key="search"
|
|
|
|
onChange={ onSearchChange }
|
|
|
|
placeholder={
|
|
|
|
labels.placeholder ||
|
|
|
|
__(
|
|
|
|
'Search by item name',
|
|
|
|
'woocommerce-admin'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
selected={ searchedLabels }
|
|
|
|
showClearButton={ true }
|
|
|
|
type={ searchBy }
|
|
|
|
disabled={ ! downloadable }
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
downloadable && (
|
|
|
|
<Button
|
|
|
|
key="download"
|
|
|
|
className="woocommerce-table__download-button"
|
|
|
|
disabled={ isLoading }
|
|
|
|
onClick={ onClickDownload }
|
|
|
|
>
|
|
|
|
<DownloadIcon />
|
|
|
|
<span className="woocommerce-table__download-button__label">
|
|
|
|
{ labels.downloadButton ||
|
|
|
|
__( 'Download', 'woocommerce-admin' ) }
|
|
|
|
</span>
|
|
|
|
</Button>
|
|
|
|
),
|
|
|
|
] }
|
|
|
|
headers={ filteredHeaders }
|
|
|
|
isLoading={ isLoading }
|
|
|
|
onQueryChange={ onQueryChange }
|
|
|
|
onColumnsChange={ onColumnsChange }
|
|
|
|
onSort={ onSort }
|
|
|
|
onPageChange={ onPageChange }
|
|
|
|
rows={ rows }
|
|
|
|
rowsPerPage={
|
|
|
|
parseInt( reportQuery.per_page, 10 ) || QUERY_DEFAULTS.pageSize
|
|
|
|
}
|
|
|
|
summary={ summary }
|
|
|
|
totalRows={ totalResults }
|
|
|
|
{ ...tableProps }
|
|
|
|
/>
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
};
|
2018-11-26 14:01:20 +00:00
|
|
|
|
|
|
|
ReportTable.propTypes = {
|
2019-10-08 22:02:26 +00:00
|
|
|
/**
|
|
|
|
* Pass in query parameters to be included in the path when onSearch creates a new url.
|
|
|
|
*/
|
|
|
|
baseSearchQuery: PropTypes.object,
|
|
|
|
/**
|
|
|
|
* The string to use as a query parameter when comparing row items.
|
|
|
|
*/
|
|
|
|
compareBy: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Url query parameter compare function operates on
|
|
|
|
*/
|
|
|
|
compareParam: PropTypes.string,
|
2018-12-13 19:24:54 +00:00
|
|
|
/**
|
|
|
|
* The key for user preferences settings for column visibility.
|
|
|
|
*/
|
|
|
|
columnPrefsKey: PropTypes.string,
|
2018-11-26 14:01:20 +00:00
|
|
|
/**
|
2018-12-22 11:46:10 +00:00
|
|
|
* 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
|
2019-11-12 18:15:55 +00:00
|
|
|
* `taxes` endpoint (ie: `/wc-analytics/reports/taxes` and `/wc/v4/reports/taxes/stats`).
|
2018-12-22 11:46:10 +00:00
|
|
|
* If the provided endpoint doesn't exist, an error will be shown to the user
|
|
|
|
* with `ReportError`.
|
2018-11-26 14:01:20 +00:00
|
|
|
*/
|
2018-12-03 03:40:57 +00:00
|
|
|
endpoint: PropTypes.string,
|
2018-12-12 12:55:10 +00:00
|
|
|
/**
|
2018-12-14 17:12:46 +00:00
|
|
|
* 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.
|
2018-12-12 12:55:10 +00:00
|
|
|
*/
|
|
|
|
extendItemsMethodNames: PropTypes.shape( {
|
2018-12-15 12:15:13 +00:00
|
|
|
getError: PropTypes.string,
|
2018-12-12 12:55:10 +00:00
|
|
|
isRequesting: PropTypes.string,
|
|
|
|
load: PropTypes.string,
|
|
|
|
} ),
|
2018-11-26 14:01:20 +00:00
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
/**
|
|
|
|
* A function that returns the summary object to build the table.
|
|
|
|
*/
|
|
|
|
getSummary: PropTypes.func,
|
|
|
|
/**
|
|
|
|
* The name of the property in the item object which contains the id.
|
|
|
|
*/
|
2018-12-03 03:40:57 +00:00
|
|
|
itemIdField: PropTypes.string,
|
2019-10-08 22:02:26 +00:00
|
|
|
/**
|
|
|
|
* Custom labels for table header actions.
|
|
|
|
*/
|
|
|
|
labels: PropTypes.shape( {
|
|
|
|
compareButton: PropTypes.string,
|
|
|
|
downloadButton: PropTypes.string,
|
|
|
|
helpText: PropTypes.string,
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
} ),
|
2018-11-26 14:01:20 +00:00
|
|
|
/**
|
2018-12-22 11:46:10 +00:00
|
|
|
* Primary data of that report. If it's not provided, it will be automatically
|
|
|
|
* loaded via the provided `endpoint`.
|
2018-11-26 14:01:20 +00:00
|
|
|
*/
|
2019-02-05 12:00:37 +00:00
|
|
|
primaryData: PropTypes.object,
|
2019-10-08 22:02:26 +00:00
|
|
|
/**
|
|
|
|
* The string to use as a query parameter when searching row items.
|
|
|
|
*/
|
|
|
|
searchBy: PropTypes.string,
|
2020-03-31 15:08:40 +00:00
|
|
|
/**
|
|
|
|
* List of fields used for summary numbers. (Reduces queries)
|
|
|
|
*/
|
|
|
|
summaryFields: PropTypes.arrayOf( PropTypes.string ),
|
2018-11-26 14:01:20 +00:00
|
|
|
/**
|
2018-12-22 11:46:10 +00:00
|
|
|
* Table data of that report. If it's not provided, it will be automatically
|
|
|
|
* loaded via the provided `endpoint`.
|
2018-11-26 14:01:20 +00:00
|
|
|
*/
|
|
|
|
tableData: PropTypes.object.isRequired,
|
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
};
|
|
|
|
|
|
|
|
ReportTable.defaultProps = {
|
2019-02-05 12:00:37 +00:00
|
|
|
primaryData: {},
|
|
|
|
tableData: {
|
|
|
|
items: {
|
|
|
|
data: [],
|
|
|
|
totalResults: 0,
|
|
|
|
},
|
|
|
|
query: {},
|
|
|
|
},
|
2018-11-26 14:01:20 +00:00
|
|
|
tableQuery: {},
|
2019-10-08 22:02:26 +00:00
|
|
|
compareParam: 'filter',
|
|
|
|
downloadable: false,
|
|
|
|
onSearch: noop,
|
|
|
|
baseSearchQuery: {},
|
2018-11-26 14:01:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export default compose(
|
|
|
|
withSelect( ( select, props ) => {
|
2019-02-26 09:28:50 +00:00
|
|
|
const {
|
|
|
|
endpoint,
|
|
|
|
getSummary,
|
|
|
|
isRequesting,
|
2019-10-08 22:02:26 +00:00
|
|
|
itemIdField,
|
2019-02-26 09:28:50 +00:00
|
|
|
query,
|
|
|
|
tableData,
|
|
|
|
tableQuery,
|
2019-03-21 03:25:05 +00:00
|
|
|
filters,
|
|
|
|
advancedFilters,
|
2020-03-31 15:08:40 +00:00
|
|
|
summaryFields,
|
2019-02-26 09:28:50 +00:00
|
|
|
} = props;
|
2019-03-21 10:35:00 +00:00
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
if (
|
|
|
|
isRequesting ||
|
|
|
|
( query.search &&
|
|
|
|
! ( query[ endpoint ] && query[ endpoint ].length ) )
|
|
|
|
) {
|
2020-06-10 16:46:46 +00:00
|
|
|
return {};
|
2019-02-05 12:00:37 +00:00
|
|
|
}
|
2020-03-25 03:20:17 +00:00
|
|
|
const { woocommerce_default_date_range: defaultDateRange } = select(
|
|
|
|
SETTINGS_STORE_NAME
|
|
|
|
).getSetting( 'wc_admin', 'wcAdminSettings' );
|
|
|
|
|
2019-03-21 03:25:05 +00:00
|
|
|
// Variations and Category charts are powered by the /reports/products/stats endpoint.
|
2020-02-14 02:23:21 +00:00
|
|
|
const chartEndpoint = [ 'variations', 'categories' ].includes(
|
|
|
|
endpoint
|
|
|
|
)
|
2019-02-07 22:39:56 +00:00
|
|
|
? 'products'
|
|
|
|
: endpoint;
|
2018-12-03 03:40:57 +00:00
|
|
|
const primaryData = getSummary
|
2019-03-21 03:25:05 +00:00
|
|
|
? getReportChartData( {
|
|
|
|
endpoint: chartEndpoint,
|
|
|
|
dataType: 'primary',
|
|
|
|
query,
|
|
|
|
select,
|
|
|
|
filters,
|
|
|
|
advancedFilters,
|
|
|
|
tableQuery,
|
2020-03-25 03:20:17 +00:00
|
|
|
defaultDateRange,
|
2020-03-31 15:08:40 +00:00
|
|
|
fields: summaryFields,
|
2020-05-29 02:32:37 +00:00
|
|
|
} )
|
2018-12-03 03:40:57 +00:00
|
|
|
: {};
|
2019-03-21 03:25:05 +00:00
|
|
|
const queriedTableData =
|
|
|
|
tableData ||
|
2020-02-14 02:23:21 +00:00
|
|
|
getReportTableData( {
|
|
|
|
endpoint,
|
|
|
|
query,
|
|
|
|
select,
|
|
|
|
tableQuery,
|
|
|
|
filters,
|
|
|
|
advancedFilters,
|
2020-03-25 03:20:17 +00:00
|
|
|
defaultDateRange,
|
2020-02-14 02:23:21 +00:00
|
|
|
} );
|
2020-05-29 02:32:37 +00:00
|
|
|
const extendedTableData = extendTableData(
|
|
|
|
select,
|
|
|
|
props,
|
|
|
|
queriedTableData
|
|
|
|
);
|
2018-11-26 14:01:20 +00:00
|
|
|
|
2019-03-21 10:35:00 +00:00
|
|
|
return {
|
2018-11-26 14:01:20 +00:00
|
|
|
primaryData,
|
2020-02-14 02:23:21 +00:00
|
|
|
ids: itemIdField
|
|
|
|
? extendedTableData.items.data.map(
|
|
|
|
( item ) => item[ itemIdField ]
|
|
|
|
)
|
|
|
|
: [],
|
2018-12-12 12:55:10 +00:00
|
|
|
tableData: extendedTableData,
|
2019-01-24 01:36:11 +00:00
|
|
|
query: { ...tableQuery, ...query },
|
2018-11-26 14:01:20 +00:00
|
|
|
};
|
2018-12-13 19:24:54 +00:00
|
|
|
} ),
|
2020-02-14 02:23:21 +00:00
|
|
|
withDispatch( ( dispatch ) => {
|
2020-06-10 16:46:46 +00:00
|
|
|
const { initiateReportExport } = dispatch(
|
2020-02-14 02:23:21 +00:00
|
|
|
'wc-api'
|
|
|
|
);
|
2018-12-13 19:24:54 +00:00
|
|
|
|
|
|
|
return {
|
2019-10-08 22:02:26 +00:00
|
|
|
initiateReportExport,
|
2018-12-13 19:24:54 +00:00
|
|
|
};
|
2018-11-26 14:01:20 +00:00
|
|
|
} )
|
|
|
|
)( ReportTable );
|