Skip to content

Commit

Permalink
Add store notice around processing historical data. (woocommerce#1763)
Browse files Browse the repository at this point in the history
* Add store notice around processing historical data.

* Cleanup

* Handle PR feedback.

* Clean up `add` logic and add empty content_data. Also add logic to get_notes_count so that we can hide unactioned statuses.

* Add the ability to update a note, and to also mark a status when an alert is clicked.

* Remove mark_actioned call on sync

* add missing todo
  • Loading branch information
justinshreve authored Mar 12, 2019
1 parent 47f6c12 commit 4c6e02a
Show file tree
Hide file tree
Showing 20 changed files with 384 additions and 98 deletions.
64 changes: 32 additions & 32 deletions client/analytics/settings/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,38 @@ const orderStatuses = Object.keys( wcSettings.orderStatuses )
} );

export const analyticsSettings = applyFilters( SETTINGS_FILTER, [
{
name: 'woocommerce_rebuild_reports_data',
label: __( 'Rebuild reports data:', 'wc-admin' ),
inputType: 'button',
inputText: __( 'Rebuild reports', 'wc-admin' ),
helpText: __(
'This tool will rebuild all of the information used by the reports. ' +
'Data will be processed in the background and may take some time depending on the size of your store.',
'wc-admin'
),
callback: ( resolve, reject, addNotice ) => {
const errorMessage = __( 'There was a problem rebuilding your report data.', 'wc-admin' );

apiFetch( { path: '/wc/v3/system_status/tools/rebuild_stats', method: 'PUT' } )
.then( response => {
if ( response.success ) {
addNotice( { status: 'success', message: response.message } );
// @todo This should be changed to detect when the lookup table population is complete.
setTimeout( () => resolve(), 300000 );
} else {
addNotice( { status: 'error', message: errorMessage } );
reject();
}
} )
.catch( error => {
if ( error && error.message ) {
addNotice( { status: 'error', message: error.message } );
}
reject();
} );
},
},
{
name: 'woocommerce_excluded_report_order_statuses',
label: __( 'Excluded Statuses:', 'wc-admin' ),
Expand Down Expand Up @@ -89,36 +121,4 @@ export const analyticsSettings = applyFilters( SETTINGS_FILTER, [
initialValue: wcSettings.wcAdminSettings.woocommerce_actionable_order_statuses || [],
defaultValue: [ 'processing', 'on-hold' ],
},
{
name: 'woocommerce_rebuild_reports_data',
label: __( 'Rebuild reports data:', 'wc-admin' ),
inputType: 'button',
inputText: __( 'Rebuild reports', 'wc-admin' ),
helpText: __(
'This tool will rebuild all of the information used by the reports. ' +
'Data will be processed in the background and may take some time depending on the size of your store.',
'wc-admin'
),
callback: ( resolve, reject, addNotice ) => {
const errorMessage = __( 'There was a problem rebuilding your report data.', 'wc-admin' );

apiFetch( { path: '/wc/v3/system_status/tools/rebuild_stats', method: 'PUT' } )
.then( response => {
if ( response.success ) {
addNotice( { status: 'success', message: response.message } );
// @todo This should be changed to detect when the lookup table population is complete.
setTimeout( () => resolve(), 300000 );
} else {
addNotice( { status: 'error', message: errorMessage } );
reject();
}
} )
.catch( error => {
if ( error && error.message ) {
addNotice( { status: 'error', message: error.message } );
}
reject();
} );
},
},
] );
45 changes: 36 additions & 9 deletions client/layout/store-alerts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { IconButton, Button, Dashicon } from '@wordpress/components';
import classnames from 'classnames';
import interpolateComponents from 'interpolate-components';
import { compose } from '@wordpress/compose';
import { noop } from 'lodash';
import { withDispatch } from '@wordpress/data';

/**
* WooCommerce dependencies
Expand Down Expand Up @@ -64,7 +66,7 @@ class StoreAlerts extends Component {
const alerts = this.props.alerts || [];
const preloadAlertCount = wcSettings.alertCount && parseInt( wcSettings.alertCount );

if ( preloadAlertCount > 0 && 0 === alerts.length ) {
if ( preloadAlertCount > 0 && this.props.isLoading ) {
return <StoreAlertsPlaceholder hasMultipleAlerts={ preloadAlertCount > 1 } />;
} else if ( 0 === alerts.length ) {
return null;
Expand All @@ -78,11 +80,22 @@ class StoreAlerts extends Component {
'is-alert-error': 'error' === type,
'is-alert-update': 'update' === type,
} );
const actions = alert.actions.map( action => (
<Button key={ action.name } isDefault href={ action.url }>
{ action.label }
</Button>
) );

const actions = alert.actions.map( action => {
const markStatus = () => {
this.props.updateNote( alert.id, { status: action.status } );
};
return (
<Button
key={ action.name }
isDefault
href={ action.url }
onClick={ '' === action.status ? noop : markStatus }
>
{ action.label }
</Button>
);
} );

return (
<Card
Expand Down Expand Up @@ -135,15 +148,29 @@ class StoreAlerts extends Component {

export default compose(
withSelect( select => {
const { getNotes } = select( 'wc-api' );
const { getNotes, isGetNotesRequesting } = select( 'wc-api' );
const alertsQuery = {
page: 1,
per_page: QUERY_DEFAULTS.pageSize,
type: 'error,update',
status: 'unactioned',
};

const alerts = getNotes( alertsQuery );
// Filter out notes that may have been marked actioned or not delayed after the initial request
const filterNotes = note => 'unactioned' === note.status;
const alerts = getNotes( alertsQuery ).filter( filterNotes );

const isLoading = isGetNotesRequesting( alertsQuery );

return { alerts };
return {
alerts,
isLoading,
};
} ),
withDispatch( dispatch => {
const { updateNote } = dispatch( 'wc-api' );
return {
updateNote,
};
} )
)( StoreAlerts );
2 changes: 2 additions & 0 deletions client/wc-api/notes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
*/
import operations from './operations';
import selectors from './selectors';
import mutations from './mutations';

export default {
operations,
selectors,
mutations,
};
10 changes: 10 additions & 0 deletions client/wc-api/notes/mutations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @format */

const updateNote = operations => ( noteId, noteFields ) => {
const resourceKey = 'note';
operations.update( [ resourceKey ], { [ resourceKey ]: { noteId, ...noteFields } } );
};

export default {
updateNote,
};
23 changes: 23 additions & 0 deletions client/wc-api/notes/operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ function read( resourceNames, fetch = apiFetch ) {
return [ ...readNotes( resourceNames, fetch ), ...readNoteQueries( resourceNames, fetch ) ];
}

function update( resourceNames, data, fetch = apiFetch ) {
return [ ...updateNote( resourceNames, data, fetch ) ];
}

function readNoteQueries( resourceNames, fetch ) {
const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'note-query' ) );

Expand Down Expand Up @@ -71,6 +75,25 @@ function readNote( resourceName, fetch ) {
} );
}

function updateNote( resourceNames, data, fetch ) {
const resourceName = 'note';
if ( resourceNames.includes( resourceName ) ) {
const { noteId, ...noteFields } = data[ resourceName ];
const url = `${ NAMESPACE }/admin/notes/${ noteId }`;
return [
fetch( { path: url, method: 'PUT', data: noteFields } )
.then( note => {
return { [ resourceName + ':' + noteId ]: { data: note } };
} )
.catch( error => {
return { [ resourceName + ':' + noteId ]: { error } };
} ),
];
}
return [];
}

export default {
read,
update,
};
2 changes: 2 additions & 0 deletions client/wc-api/wc-api-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function createWcApiSpec() {
mutations: {
...settings.mutations,
...user.mutations,
...notes.mutations,
},
selectors: {
...items.selectors,
Expand All @@ -42,6 +43,7 @@ function createWcApiSpec() {
return [
...settings.operations.update( resourceNames, data ),
...user.operations.update( resourceNames, data ),
...notes.operations.update( resourceNames, data ),
];
},
},
Expand Down
87 changes: 82 additions & 5 deletions includes/api/class-wc-admin-rest-admin-notes-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public function register_routes() {
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_items_permissions_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
Expand Down Expand Up @@ -124,6 +129,12 @@ public function get_items( $request ) {
$args['type'] = $type;
}

$status = isset( $request['status'] ) ? $request['status'] : '';
$status = sanitize_text_field( $status );
if ( ! empty( $status ) ) {
$args['status'] = $status;
}

$notes = WC_Admin_Notes::get_notes( 'edit', $args );

$data = array();
Expand All @@ -134,7 +145,7 @@ public function get_items( $request ) {
}

$response = rest_ensure_response( $data );
$response->header( 'X-WP-Total', WC_Admin_Notes::get_notes_count() );
$response->header( 'X-WP-Total', WC_Admin_Notes::get_notes_count( $type, $status ) );

return $response;
}
Expand Down Expand Up @@ -167,6 +178,49 @@ public function get_items_permissions_check( $request ) {
return true;
}

/**
* Update a single note.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Request|WP_Error
*/
public function update_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 )
);
}

// @todo Status is the only field that can be updated at the moment. We should also implement the "date reminder" setting.
$note_changed = false;
if ( ! is_null( $request->get_param( 'status' ) ) ) {
$note->set_status( $request->get_param( 'status' ) );
$note_changed = true;
}

if ( $note_changed ) {
$note->save();
}
return $this->get_item( $request );
}

/**
* Makes sure the current user has access to WRITE the settings APIs.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function update_items_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wc-admin' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}

/**
* Prepare a path or query for serialization to the client.
*
Expand Down Expand Up @@ -204,8 +258,9 @@ public function prepare_item_for_response( $data, $request ) {
$data['title'] = stripslashes( $data['title'] );
$data['content'] = stripslashes( $data['content'] );
foreach ( (array) $data['actions'] as $key => $value ) {
$data['actions'][ $key ]->label = stripslashes( $data['actions'][ $key ]->label );
$data['actions'][ $key ]->url = $this->prepare_query_for_response( $data['actions'][ $key ]->query );
$data['actions'][ $key ]->label = stripslashes( $data['actions'][ $key ]->label );
$data['actions'][ $key ]->url = $this->prepare_query_for_response( $data['actions'][ $key ]->query );
$data['actions'][ $key ]->status = stripslashes( $data['actions'][ $key ]->status );
}
$data = $this->filter_response_by_context( $data, $context );

Expand Down Expand Up @@ -233,6 +288,29 @@ public function prepare_item_for_response( $data, $request ) {
return apply_filters( 'woocommerce_rest_prepare_admin_note', $response, $data, $request );
}

/**
* 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['type'] = array(
'description' => __( 'Type of note.', 'wc-admin' ),
'type' => 'string',
'enum' => WC_Admin_Note::get_allowed_types(),
'validate_callback' => 'rest_validate_request_arg',
);
$params['status'] = array(
'description' => __( 'Status of note.', 'wc-admin' ),
'type' => 'string',
'enum' => WC_Admin_Note::get_allowed_statuses(),
'validate_callback' => 'rest_validate_request_arg',
);
return $params;
}

/**
* Get the note's schema, conforming to JSON Schema.
*
Expand Down Expand Up @@ -296,7 +374,6 @@ public function get_item_schema() {
'description' => __( 'The status of the note (e.g. unactioned, actioned).', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'source' => array(
'description' => __( 'Source of the note.', 'wc-admin' ),
Expand All @@ -320,7 +397,7 @@ public function get_item_schema() {
'description' => __( 'Date after which the user should be reminded of the note, if any.', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
'readonly' => true, // @todo Allow date_reminder to be updated.
),
'date_reminder_gmt' => array(
'description' => __( 'Date after which the user should be reminded of the note, if any (GMT).', 'wc-admin' ),
Expand Down
5 changes: 4 additions & 1 deletion includes/class-wc-admin-install.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class WC_Admin_Install {
*
* @todo get this dynamically?
*/
const VERSION_NUMBER = '0.6.0';
const VERSION_NUMBER = '0.8.0';

/**
* Plugin version option name.
Expand Down Expand Up @@ -76,6 +76,8 @@ public static function install() {
self::create_tables();
self::update_wc_admin_version();

WC_Admin_Notes_Historical_Data::add_note();

delete_transient( 'wc_admin_installing' );

do_action( 'wc_admin_installed' );
Expand Down Expand Up @@ -174,6 +176,7 @@ private static function get_schema() {
name varchar(255) NOT NULL,
label varchar(255) NOT NULL,
query longtext NOT NULL,
status varchar(255) NOT NULL,
PRIMARY KEY (action_id),
KEY note_id (note_id)
) $collate;
Expand Down
Loading

0 comments on commit 4c6e02a

Please sign in to comment.