Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/logging #42

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c134b03
Add process logs to the API side.
phatsk Feb 13, 2018
73531a8
Merge branch 'master' into feature/logging
phatsk Feb 14, 2018
786eddb
return process logs in semi-consistent fashion.
phatsk Feb 14, 2018
ecf8386
Add logging to the bulk sync page!
phatsk Feb 14, 2018
dd1c804
Merge branch 'feature/logging' of github.com:phatsk/press-sync into f…
phatsk Feb 14, 2018
efd551e
Merge branch 'master' into feature/logging
phatsk Feb 23, 2018
ff2d310
Clean up logging Javascript.
phatsk Feb 26, 2018
5df1445
Add some helper methods for logging API responses.
phatsk Feb 26, 2018
e84af2f
Fix datepicker JS and styles.
phatsk Feb 26, 2018
a7503c6
Add better connection handling.
phatsk Feb 26, 2018
3eeecb7
Send a reasonable response when the press sync key is invalid.
phatsk Feb 26, 2018
5e6e3bf
Format and log sync responses.
phatsk Feb 26, 2018
203aa80
Log ALL the things.
phatsk Feb 26, 2018
a817b8e
Whitespace fixes.
phatsk Feb 26, 2018
07436b0
Fix partial term sync check for edge case.
phatsk Feb 26, 2018
afd0225
Cleanup log view.
phatsk Feb 26, 2018
e7b0c26
Display last connection error on credentials page.
phatsk Feb 26, 2018
4c64c64
Merge branch 'master' into feature/logging
phatsk Feb 26, 2018
ee2c104
Update references to correct key.
phatsk Feb 26, 2018
0a0d6e2
Add ability to download log as a text file.
phatsk Feb 26, 2018
2d7fd73
Add docblock and attribution for download blob method.
phatsk Feb 26, 2018
109fda8
Fix term syncing
phatsk Apr 20, 2018
677e4d7
Some phpcs cleanup
phatsk Apr 20, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 197 additions & 19 deletions assets/js/press-sync.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,83 @@
window.PressSync = ( function( window, document, $ ) {

var app = {};

app.PAGE_SIZE = 1;
var app = {
PAGE_SIZE: 1,
LOG_LIMIT: 20, // Limit how many log entries to show, previous logs will be discarded.
log_index: 0, // Count how many logs have processed.
times: [], // Array of times used to calculate time remaining average more accurately.
elCache: {},
logFileURL: null
};

/**
* Initialize the JS app for Press Sync.
*
* Handles registering elements to the element Cache and binding inital listeners.
*
* @since 0.1.0
*/
app.init = function() {
$(document).on( 'click', '.press-sync-button', app.pressSyncButton );
app.elCache.syncButton = $('#press-sync-button');
app.elCache.cancelButton = $('#press-sync-cancel-button');
app.elCache.status = $('.progress-stats');
app.elCache.bulkSettings = $('#press-sync-bulk-settings');
app.elCache.logView = $('#press-sync-log-view' );
app.elCache.logs = $('#press-sync-logs');
app.elCache.downloadLog = $('#press-sync-download-log');

app.elCache.syncButton.on( 'click', app.pressSyncButton );
app.elCache.cancelButton.on( 'click', app.cancelSync );
app.elCache.downloadLog.on( 'click', app.downloadLog );
};

/**
* Handles the Press Sync "Sync" button.
*
* @since NEXT
* @param Object click_event The click event from the listener.
*/
app.pressSyncButton = function( click_event ) {
app.running = true;

// @TODO probably should have this in a method similar to app.cleanup.
app.elCache.syncButton.hide();
app.elCache.cancelButton.show();
app.elCache.bulkSettings.hide();
app.elCache.logView.show();
app.elCache.logs.val('');
app.loadProgressBar();
return;
}
};

/**
* Set the app.running flag to false to stop the current sync process.
*
* @since NEXT
*/
app.cancelSync = function() {
app.running = false;
};

/**
* Update the timing array and smooth out timing samples.
*
* @since NEXT
* @param Number remaining_time The most recent remaining time estimate.
*/
app.updateTiming = function( remaining_time ) {
app.times.push( remaining_time );

// Limit sample size.
if ( 100 < app.times.length ) {
app.times.shift();
}

app.times.map( function ( e ) {
return e += e;
} );

app.times = smooth( app.times, 0.85 );
};

app.loadProgressBar = function() {
$('.press-sync-button').hide();
Expand Down Expand Up @@ -72,24 +138,25 @@ window.PressSync = ( function( window, document, $ ) {

if ( request_time ) {
// Estimate time remaining.
var remaining_time = ( ( ( total_objects - total_objects_processed ) / app.PAGE_SIZE ) * request_time );
remaining_time = remaining_time / 60 / 60;
var time_left_suffix = 'hours';
var remaining_time = ( ( ( total_objects - total_objects_processed ) / app.PAGE_SIZE ) * request_time );
app.updateTiming( remaining_time );
remaining_time = remaining_time / app.times.length;
remaining_time = remaining_time / 60 / 60;

// Shift to minutes.
if ( 1 > remaining_time ) {
remaining_time = remaining_time * 60;
remaining_time = remaining_time * 60;
time_left_suffix = 'minutes';
}

// Round to two decimal places, mostly.
remaining_time = Math.round( remaining_time * 100 ) / 100;

progress_string += ' (' + [ 'Estimated time remaining:', remaining_time, time_left_suffix ].join(' ') + ')';
remaining_time = Math.round( remaining_time * 100 ) / 100;
progress_string += ' (' + [ 'Estimated time remaining:', remaining_time, time_left_suffix ].join(' ') + ' )';
}

$('.progress-stats').text( progress_string );
}
};

/**
* Syncs data to the remote site.
Expand Down Expand Up @@ -117,29 +184,140 @@ window.PressSync = ( function( window, document, $ ) {
objects_to_sync: objects_to_sync
}
}).done(function( response ) {
// Convert request time from milliseconds to seconds.
var request_time = ( new Date().getTime() - start_time ) / 1000;
if ( ! app.running ) {
app.cleanup( 'Sync canceled by user.' );
return;
}

app.updateProgressBar( response.data.objects_to_sync, response.data.total_objects_processed, response.data.total_objects, request_time );
app.updateProgressBar(
response.data.ps_objects_to_sync,
response.data.total_objects_processed,
response.data.total_objects,
( new Date().getTime() - start_time ) / 1000 // Convert request time from milliseconds to seconds.
);

app.Log( response );

// Bail if we're done.
if ( response.data.total_objects_processed >= response.data.total_objects ) {
// Start the next batch at page 1.
if ( next_args && next_args.order_to_sync_all && next_args.order_to_sync_all.length ) {
return app.syncData( 1, null, next_args );
}

$('.press-sync-button').show();
$('.progress-stats').text('Sync completed!');
app.cleanup( 'Sync completed!' );
return;
}

app.syncData( response.data.next_page, response.data.objects_to_sync, next_args );
app.syncData( response.data.next_page, response.data.ps_objects_to_sync, next_args );
});

}

/**
* Logs messages from the remote server to the log window.
*
* @since NEXT
* @param Object response The response from the AJAX request.
*/
app.Log = function( response ) {
if ( ! response.data ) {
return;
}

var loglines = [];

try {
var logs = response.data.log;
for ( var i = 0; i < logs.length; i++) {
loglines.push( logs[i] );
}

loglines.push("\n---BATCH END ---\n");
app.elCache.logs.val( app.elCache.logs.val() + loglines.join("\n") );
} catch ( e ) {
console.warn( "Could not log data, response: " + e );
console.warn( response.data );
}
};

/**
* Cleanup the view so it's back to a state similar to when we first
* visit the page.
*
* @since NEXT
* @param string message The message to display under the progress bar.
*/
app.cleanup = function( message ){
app.elCache.syncButton.show();
app.elCache.cancelButton.hide();
app.elCache.bulkSettings.show();
app.elCache.status.text( message );
createLogFile();
app.elCache.downloadLog.show();
};

/**
* Click handler to download the log file.
*
* @since NEXT
*/
app.downloadLog = function() {
app.elCache.downloadLog.attr( 'href', app.logFileURL );
};

$( document ).ready( app.init );

return app;

// Private methods.

/**
* Smooth a set of values.
*
* We use this to smooth out the timings in the array of request times to give a more accurate
* time estimation.
*
* Source: https://stackoverflow.com/q/32788836/1169389
*/
function smooth(values, alpha) {
var weighted = average(values) * alpha;
var smoothed = [];
for (var i in values) {
var curr = values[i];
var prev = smoothed[i - 1] || values[values.length - 1];
var next = curr || values[0];
var improved = Number(average([weighted, prev, curr, next]).toFixed(2));
smoothed.push(improved);
}
return smoothed;
}

/**
* Gets the averate of a set of data.
*
* Source: https://stackoverflow.com/q/32788836/1169389
*/
function average(data) {
var sum = data.reduce(function(sum, value) {
return sum + value;
}, 0);
var avg = sum / data.length;
return avg;
}

/**
* Creates a downloadable file using the Javascript Blob object.
*
* Source: https://stackoverflow.com/a/21016088/1169389
*/
function createLogFile() {
var text = app.elCache.logs.val();
var data = new Blob([text], {type: 'text/plain'});

if ( null !== app.logFileURL ) {
window.URL.revokeObjectURL( app.logFileURL );
}

app.logFileURL = window.URL.createObjectURL(data);
}
} )( window, document, jQuery );
Loading