diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 44f29eb854d..8c19e3d2177 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -248,6 +248,8 @@ Optimizations * SOLR-3840: XML query response display is unreadable in Solr Admin Query UI (steffkes) +* SOLR-3982: Admin UI: Various Dataimport Improvements (steffkes) + Bug Fixes ---------------------- diff --git a/solr/webapp/web/css/styles/dataimport.css b/solr/webapp/web/css/styles/dataimport.css index 48f64bb0af8..712d137226f 100644 --- a/solr/webapp/web/css/styles/dataimport.css +++ b/solr/webapp/web/css/styles/dataimport.css @@ -29,7 +29,7 @@ #content #dataimport #form #navigation .current a { - background-image: url( ../../img/ico/document-import.png ); + background-image: url( ../../img/ico/status.png ); } #content #dataimport #form form @@ -60,27 +60,41 @@ width: 100%; } +#content #dataimport #form input +{ + width: 98%; +} + #content #dataimport #form button { margin-top: 10px; } -#content #dataimport #form button.loader +#content #dataimport #form .execute span { - background-position: 2px 50%; - padding-left: 23px; + background-image: url( ../../img/ico/document-import.png ); +} + +#content #dataimport #form .refresh-status span +{ + background-image: url( ../../img/ico/arrow-circle.png ); +} + +#content #dataimport #form .refresh-status span.success +{ + background-image: url( ../../img/ico/tick.png ); } #content #dataimport #form #start { float: left; - margin-right: 2%; - width: 49%; + width: 47%; } #content #dataimport #form #rows { - width: 49%; + float: right; + width: 47%; } #content #dataimport #form .checkbox input @@ -89,9 +103,33 @@ width: auto; } +#content #dataimport #form #auto-refresh-status +{ + margin-top: 20px; +} + +#content #dataimport #form #auto-refresh-status a +{ + background-image: url( ../../img/ico/ui-check-box-uncheck.png ); + background-position: 0 50%; + color: #c0c0c0; + display: block; + padding-left: 21px; +} + +#content #dataimport #form #auto-refresh-status a.on, +#content #dataimport #form #auto-refresh-status a:hover +{ + color: #333; +} + +#content #dataimport #form #auto-refresh-status a.on +{ + background-image: url( ../../img/ico/ui-check-box.png ); +} + #content #dataimport #current_state { - display: none; padding: 10px; margin-bottom: 20px; } @@ -117,6 +155,30 @@ #content #dataimport #current_state .info { background-position: 0 1px; + position: relative; +} + +#content #dataimport #current_state .info .details span +{ + color: #c0c0c0; +} + +#content #dataimport #current_state .info .abort-import +{ + display: none; + position: absolute; + right: 0px; + top: 0px; +} + +#content #dataimport #current_state .info .abort-import span +{ + background-image: url( ../../img/ico/cross.png ); +} + +#content #dataimport #current_state .info .abort-import.success span +{ + background-image: url( ../../img/ico/tick.png ); } #content #dataimport #current_state.indexing @@ -124,6 +186,16 @@ background-color: #f9f9f9; } +#content #dataimport #current_state.indexing .info +{ + background-image: url( ../../img/ico/hourglass.png ); +} + +#content #dataimport #current_state.indexing .info .abort-import +{ + display: block; +} + #content #dataimport #current_state.success { background-color: #e6f3e6; @@ -139,6 +211,21 @@ color: #080; } +#content #dataimport #current_state.aborted +{ + background-color: #f3e6e6; +} + +#content #dataimport #current_state.aborted .info +{ + background-image: url( ../../img/ico/slash.png ); +} + +#content #dataimport #current_state.aborted .info strong +{ + color: #800; +} + #content #dataimport #current_state.failure { background-color: #f3e6e6; @@ -146,7 +233,7 @@ #content #dataimport #current_state.failure .info { - background-image: url( ../../img/ico/slash.png ); + background-image: url( ../../img/ico/cross-button.png ); } #content #dataimport #current_state.failure .info strong @@ -154,7 +241,17 @@ color: #800; } -#content #dataimport #config-error +#content #dataimport #current_state.idle +{ + background-color: #e6e6ff; +} + +#content #dataimport #current_state.idle .info +{ + background-image: url( ../../img/ico/information.png ); +} + +#content #dataimport #error { background-color: #f00; background-image: url( ../../img/ico/construction.png ); @@ -167,37 +264,43 @@ padding-left: 35px; } -#content #dataimport #config h2 +#content #dataimport .block h2 { border-color: #c0c0c0; padding-left: 5px; position: relative; } -#content #dataimport #config.hidden h2 +#content #dataimport .block.hidden h2 { border-color: #fafafa; } -#content #dataimport #config h2 a.toggle +#content #dataimport .block h2 a.toggle { background-image: url( ../../img/ico/toggle-small.png ); background-position: 0 50%; padding-left: 21px; } -#content #dataimport #config.hidden h2 a.toggle +#content #dataimport .block.hidden h2 a.toggle { background-image: url( ../../img/ico/toggle-small-expand.png ); } +#content #dataimport #config h2 a.r +{ + background-position: 3px 50%; + display: block; + float: right; + margin-left: 10px; + padding-left: 24px; + padding-right: 3px; +} + #content #dataimport #config h2 a.reload_config { background-image: url( ../../img/ico/arrow-circle.png ); - padding-left: 21px; - position: absolute; - right: 5px; - top: 5px; } #content #dataimport #config h2 a.reload_config.success @@ -210,13 +313,72 @@ background-image: url( ../../img/ico/slash.png ); } -#content #dataimport #config.hidden .content +#content #dataimport #config h2 a.debug_mode +{ + background-image: url( ../../img/ico/hammer.png ); + color: #c0c0c0; +} + +#content #dataimport #config.debug_mode h2 a.debug_mode +{ + background-color: #ff0; + background-image: url( ../../img/ico/hammer-screwdriver.png ); + color: #333; +} + +#content #dataimport .block.hidden .content { display: none; } +#content #dataimport #config .content +{ + padding: 5px 2px; +} + #content #dataimport #dataimport_config .loader { background-position: 0 50%; padding-left: 21px; +} + +#content #dataimport #dataimport_config .formatted +{ + border: 1px solid #fff; + display: block; + padding: 2px; +} + +#content #dataimport .debug_mode #dataimport_config .formatted +{ + display: none; +} + +#content #dataimport #dataimport_config .editable +{ + display: none; +} + +#content #dataimport .debug_mode #dataimport_config .editable +{ + display: block; +} + +#content #dataimport #dataimport_config .editable textarea +{ + font-family: monospace; + height: 120px; + min-height: 60px; + width: 100%; +} + +#content #dataimport #debug_response +{ + display: none; +} + +#content #dataimport #debug_response em +{ + color: #c0c0c0; + font-style: normal; } \ No newline at end of file diff --git a/solr/webapp/web/img/ico/cross-button.png b/solr/webapp/web/img/ico/cross-button.png new file mode 100755 index 00000000000..933272b4939 Binary files /dev/null and b/solr/webapp/web/img/ico/cross-button.png differ diff --git a/solr/webapp/web/img/ico/hammer.png b/solr/webapp/web/img/ico/hammer.png new file mode 100755 index 00000000000..cf0ef85a78b Binary files /dev/null and b/solr/webapp/web/img/ico/hammer.png differ diff --git a/solr/webapp/web/js/lib/jquery.autogrow.js b/solr/webapp/web/js/lib/jquery.autogrow.js new file mode 100755 index 00000000000..1a41a62f77b --- /dev/null +++ b/solr/webapp/web/js/lib/jquery.autogrow.js @@ -0,0 +1,132 @@ +/* + * Auto Expanding Text Area (1.2.2) + * by Chrys Bader (www.chrysbader.com) + * chrysb@gmail.com + * + * Special thanks to: + * Jake Chapa - jake@hybridstudio.com + * John Resig - jeresig@gmail.com + * + * Copyright (c) 2008 Chrys Bader (www.chrysbader.com) + * Licensed under the GPL (GPL-LICENSE.txt) license. + * + * + * NOTE: This script requires jQuery to work. Download jQuery at www.jquery.com + * + */ + +(function(jQuery) { + + var self = null; + + jQuery.fn.autogrow = function(o) + { + return this.each(function() { + new jQuery.autogrow(this, o); + }); + }; + + + /** + * The autogrow object. + * + * @constructor + * @name jQuery.autogrow + * @param Object e The textarea to create the autogrow for. + * @param Hash o A set of key/value pairs to set as configuration properties. + * @cat Plugins/autogrow + */ + + jQuery.autogrow = function (e, o) + { + this.options = o || {}; + this.dummy = null; + this.interval = null; + this.line_height = this.options.lineHeight || parseInt(jQuery(e).css('line-height'), 10); + this.min_height = this.options.minHeight || parseInt(jQuery(e).css('min-height'), 10); + this.max_height = this.options.maxHeight || parseInt(jQuery(e).css('max-height'), 10); + this.textarea = jQuery(e); + + if(this.line_height == NaN) + this.line_height = 0; + + // Only one textarea activated at a time, the one being used + this.init(); + }; + + jQuery.autogrow.fn = jQuery.autogrow.prototype = { + autogrow: '1.2.2' + }; + + jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend; + + jQuery.autogrow.fn.extend({ + + init: function() { + var self = this; + this.textarea.css({overflow: 'hidden', display: 'block'}); + this.textarea.bind('focus', function() { self.startExpand(); } ).bind('blur', function() { self.stopExpand(); }); + this.checkExpand(); + }, + + startExpand: function() { + var self = this; + this.interval = window.setInterval(function() {self.checkExpand();}, 400); + }, + + stopExpand: function() { + clearInterval(this.interval); + }, + + checkExpand: function() { + + if (this.dummy == null) + { + this.dummy = jQuery('
'); + this.dummy.css({ + 'font-size' : this.textarea.css('font-size'), + 'font-family': this.textarea.css('font-family'), + 'width' : this.textarea.css('width'), + // IE shits its pants if you uncomment the next line! + //'padding' : this.textarea.css('padding'), + 'line-height': this.line_height + 'px', + 'overflow-x' : 'hidden', + 'position' : 'absolute', + 'top' : 0, + 'left' : -9999 + }).appendTo('body'); + } + + // Strip HTML tags + var html = this.textarea.val().replace(/(<|>)/g, ''); + + // IE is different, as per usual + if ($.browser.msie) + { + html = html.replace(/\n/g, '
new'); + } + else + { + html = html.replace(/\n/g, '
new'); + } + + if (this.dummy.html() != html) + { + this.dummy.html(html); + + if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height)) + { + this.textarea.css('overflow-y', 'auto'); + } + else + { + this.textarea.css('overflow-y', 'hidden'); + if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height())) + { + this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100); + } + } + } + } + }); +})(jQuery); diff --git a/solr/webapp/web/js/main.js b/solr/webapp/web/js/main.js index 8c91f3d9fd0..b66bc587768 100644 --- a/solr/webapp/web/js/main.js +++ b/solr/webapp/web/js/main.js @@ -20,6 +20,7 @@ require [ 'lib/order!lib/console', 'lib/order!jquery', + 'lib/order!lib/jquery.autogrow', 'lib/order!lib/jquery.cookie', 'lib/order!lib/jquery.form', 'lib/order!lib/jquery.jstree', diff --git a/solr/webapp/web/js/scripts/app.js b/solr/webapp/web/js/scripts/app.js index 4e23b22af5c..d4dccd20ec6 100644 --- a/solr/webapp/web/js/scripts/app.js +++ b/solr/webapp/web/js/scripts/app.js @@ -82,11 +82,7 @@ var sammy = $.sammy {}, function( context ) { - if( app.timeout ) - { - console.debug( 'Clearing Timeout #' + app.timeout ); - clearTimeout( app.timeout ); - } + app.clear_timeout(); var menu_wrapper = $( '#menu-wrapper' ); @@ -399,7 +395,78 @@ var solr_admin = function( app_config ) } } ); - } + }; + + this.convert_duration_to_seconds = function convert_duration_to_seconds( str ) + { + var seconds = 0; + var arr = new String( str || '' ).split( '.' ); + var parts = arr[0].split( ':' ).reverse(); + var parts_count = parts.length; + + for( var i = 0; i < parts_count; i++ ) + { + seconds += ( parseInt( parts[i], 10 ) || 0 ) * Math.pow( 60, i ); + } + + // treat more or equal than .5 as additional second + if( arr[1] && 5 <= parseInt( arr[1][0], 10 ) ) + { + seconds++; + } + + return seconds; + }; + + this.convert_seconds_to_readable_time = function convert_seconds_to_readable_time( seconds ) + { + seconds = parseInt( seconds || 0, 10 ); + var minutes = Math.floor( seconds / 60 ); + var hours = Math.floor( minutes / 60 ); + + var text = []; + if( 0 !== hours ) + { + text.push( hours + 'h' ); + seconds -= hours * 60 * 60; + minutes -= hours * 60; + } + + if( 0 !== minutes ) + { + text.push( minutes + 'm' ); + seconds -= minutes * 60; + } + + if( 0 !== seconds ) + { + text.push( ( '0' + seconds ).substr( -2 ) + 's' ); + } + + return text.join( ' ' ); + }; + + this.clear_timeout = function clear_timeout() + { + if( !app.timeout ) + { + return false; + } + + console.debug( 'Clearing Timeout #' + this.timeout ); + clearTimeout( this.timeout ); + this.timeout = null; + }; + + this.format_json = function format_json( json_str ) + { + if( JSON.stringify && JSON.parse ) + { + json_str = JSON.stringify( JSON.parse( json_str ), undefined, 2 ); + } + + return json_str; + }; }; diff --git a/solr/webapp/web/js/scripts/dataimport.js b/solr/webapp/web/js/scripts/dataimport.js index 8f0e183c5bc..15a65dd8fdf 100644 --- a/solr/webapp/web/js/scripts/dataimport.js +++ b/solr/webapp/web/js/scripts/dataimport.js @@ -15,48 +15,8 @@ limitations under the License. */ -var convert_duration_to_seconds = function( str ) -{ - var ret = 0; - var parts = new String( str ).split( '.' ).shift().split( ':' ).reverse(); - var parts_count = parts.length; - - for( var i = 0; i < parts_count; i++ ) - { - ret += parseInt( parts[i], 10 ) * Math.pow( 60, i ); - } - - return ret; -} - -var convert_seconds_to_readable_time = function( value ) -{ - var text = []; - value = parseInt( value ); - - var minutes = Math.floor( value / 60 ); - var hours = Math.floor( minutes / 60 ); - - if( 0 !== hours ) - { - text.push( hours + 'h' ); - value -= hours * 60 * 60; - minutes -= hours * 60; - } - - if( 0 !== minutes ) - { - text.push( minutes + 'm' ); - value -= minutes * 60; - } - - if( 0 !== value ) - { - text.push( value + 's' ); - } - - return text.join( ' ' ); -} +var dataimport_timeout = 2000; +var cookie_dataimport_autorefresh = 'dataimport_autorefresh'; sammy.bind ( @@ -152,7 +112,11 @@ sammy.get var dataimport_element = $( '#dataimport', content_element ); var form_element = $( '#form', dataimport_element ); var config_element = $( '#config', dataimport_element ); - var config_error_element = $( '#config-error', dataimport_element ); + var error_element = $( '#error', dataimport_element ); + var debug_response_element = $( '#debug_response', dataimport_element ); + + var autorefresh_status = false; + var debug_mode = false; // handler @@ -195,24 +159,23 @@ sammy.get $.ajax ( { - url : handler_url + '?command=show-config', + url : handler_url + '?command=show-config&indent=true', dataType : 'xml', context : $( '#dataimport_config', config_element ), beforeSend : function( xhr, settings ) { + error_element + .empty() + .hide(); }, success : function( config, text_status, xhr ) { dataimport_element .removeClass( 'error' ); - - config_error_element - .hide(); config_element .addClass( 'hidden' ); - var entities = [ '' ]; $( 'document > entity', config ) @@ -226,6 +189,9 @@ sammy.get $( '#entity', form_element ) .html( entities.join( "\n" ) ); + + $( '.editable textarea', this ) + .val( xhr.responseText.replace( /\n+$/, '' ) ); }, error : function( xhr, text_status, error_thrown ) { @@ -234,7 +200,8 @@ sammy.get dataimport_element .addClass( 'error' ); - config_error_element + error_element + .text( 'Dataimport XML-Configuration is not valid' ) .show(); config_element @@ -248,7 +215,7 @@ sammy.get xhr.responseText.esc() + '' ); - this.html( code ); + $( '.formatted', this ).html( code ); if( 'success' === text_status ) { @@ -260,7 +227,7 @@ sammy.get } dataimport_fetch_config(); - $( '.toggle', config_element ) + $( '.block .toggle', dataimport_element ) .die( 'click' ) .live ( @@ -325,160 +292,339 @@ sammy.get ); return false; } - ) + ); + + var debug_mode_element = $( '.debug_mode', config_element ); + debug_mode_element + .die( 'click' ) + .live + ( + 'click', + function( event ) + { + var self = $( this ); + var block = self.closest( '.block' ) + + var debug_checkbox = $( 'input[name="debug"]', form_element ); + var submit_span = $( 'button[type="submit"] span', form_element ); + + debug_mode = !debug_mode; + + block.toggleClass( 'debug_mode', debug_mode ); + + if( debug_mode ) + { + block.removeClass( 'hidden' ); + + debug_checkbox + .attr( 'checked', 'checked' ) + .trigger( 'change' ); + + submit_span + .data( 'original', submit_span.text() ) + .text( submit_span.data( 'debugmode' ) ); + + $( 'textarea', block ) + .autogrow() + } + else + { + submit_span + .text( submit_span.data( 'original' ) ) + .removeData( 'original' ); + } + } + ); + + // abort + + var abort_import_element = $( '.abort-import', dataimport_element ); + abort_import_element + .off( 'click' ) + .on + ( + 'click', + function( event ) + { + var span_element = $( 'span', this ); + + $.ajax + ( + { + url : handler_url + '?command=abort&wt=json', + dataType : 'json', + type: 'POST', + context: $( this ), + beforeSend : function( xhr, settings ) + { + span_element + .addClass( 'loader' ); + }, + success : function( response, text_status, xhr ) + { + span_element + .data( 'original', span_element.text() ) + .text( span_element.data( 'aborting' ) ); + + this + .removeClass( 'warn' ) + .addClass( 'success' ); + + window.setTimeout + ( + function() + { + $( 'span', abort_import_element ) + .removeClass( 'loader' ) + .text( span_element.data( 'original' ) ) + .removeData( 'original' ); + + abort_import_element + .removeClass( 'success' ) + .addClass( 'warn' ); + }, + dataimport_timeout * 2 + ); + + dataimport_fetch_status(); + } + } + ); + return false; + } + ); // state + + var status_button = $( 'form button.refresh-status', form_element ); + + status_button + .off( 'click' ) + .on + ( + 'click', + function( event ) + { + dataimport_fetch_status(); + return false; + } + ) + .trigger( 'click' ); - function dataimport_fetch_status() + function dataimport_fetch_status( clear_timeout ) { + if( clear_timeout ) + { + app.clear_timeout(); + } + $.ajax ( { - url : handler_url + '?command=status', - dataType : 'xml', + url : handler_url + '?command=status&indent=true&wt=json', + dataType : 'json', beforeSend : function( xhr, settings ) { + $( 'span', status_button ) + .addClass( 'loader' ); }, success : function( response, text_status, xhr ) { var state_element = $( '#current_state', content_element ); + var time_element = $( '.time', state_element ); - var status = $( 'str[name="status"]', response ).text(); - var rollback_element = $( 'str[name="Rolledback"]', response ); - var messages_count = $( 'lst[name="statusMessages"] str', response ).size(); + var status = response.status; + var rollback_time = response.statusMessages.Rolledback || null; + var abort_time = response.statusMessages.Aborted || null; + + var messages = response.statusMessages; + var messages_count = 0; + for( var key in messages ) { messages_count++; } - var started_at = $( 'str[name="Full Dump Started"]', response ).text(); - if( !started_at ) + var format_number = function format_number( number ) { - started_at = (new Date()).toGMTString(); - } + return ( number || 0 ).toString().replace( /\B(?=(\d{3})+(?!\d))/g, '\'' ); + }; - function dataimport_compute_details( response, details_element ) + function dataimport_compute_details( response, details_element, elapsed_seconds ) { + var config = { + 'Requests' : 'Total Requests made to DataSource', + 'Fetched' : 'Total Rows Fetched', + 'Skipped' : 'Total Documents Skipped', + 'Processed' : 'Total Documents Processed' + }; + var details = []; - - var requests = parseInt( $( 'str[name="Total Requests made to DataSource"]', response ).text(), 10 ); - if( requests ) + for( var key in config ) { - details.push - ( - 'Requests: ' + - requests - ); - } + var value = parseInt( response.statusMessages[config[key]], 10 ); - var fetched = parseInt( $( 'str[name="Total Rows Fetched"]', response ).text(), 10 ); - if( fetched ) - { - details.push - ( - 'Fetched: ' + - fetched - ); - } + var detail = '' + key.esc() + ': ' + format_number( value ).esc(); + if( elapsed_seconds && 'skipped' !== key.toLowerCase() ) + { + detail += ' (' + format_number( Math.round( value / elapsed_seconds ) ).esc() + '/s)' + } - var skipped = parseInt( $( 'str[name="Total Documents Skipped"]', response ).text(), 10 ); - if( requests ) - { - details.push - ( - 'Skipped: ' + - skipped - ); - } - - var processed = parseInt( $( 'str[name="Total Documents Processed"]', response ).text(), 10 ); - if( processed ) - { - details.push - ( - 'Processed: ' + - processed - ); - } + details.push( detail ); + }; details_element .html( details.join( ', ' ) ) .show(); + }; + + var get_time_taken = function get_default_time_taken() + { + var time_taken_text = response.statusMessages['Time taken']; + return app.convert_duration_to_seconds( time_taken_text ); + }; + + var get_default_info_text = function default_info_text() + { + var info_text = response.statusMessages[''] || ''; + + // format numbers included in status nicely + info_text = info_text.replace + ( + /\d{4,}/g, + function( match, position, string ) + { + return format_number( parseInt( match, 10 ) ); + } + ); + + var time_taken_text = app.convert_seconds_to_readable_time( get_time_taken() ); + if( time_taken_text ) + { + info_text += ' (Duration: ' + time_taken_text.esc() + ')'; + } + + return info_text; + }; + + var show_info = function show_info( info_text, elapsed_seconds ) + { + $( '.info strong', state_element ) + .text( info_text || get_default_info_text() ); + + $( '.info .details', state_element ) + .hide(); + }; + + var show_full_info = function show_full_info( info_text, elapsed_seconds ) + { + show_info( info_text, elapsed_seconds ); + + dataimport_compute_details + ( + response, + $( '.info .details', state_element ), + elapsed_seconds || get_time_taken() + ); + }; + + var set_time = function set_time( time_text ) + { + time_element + .text( time_text ) + .removeData( 'timeago' ) + .timeago() + .show(); } state_element - .removeClass( 'indexing' ) - .removeClass( 'success' ) - .removeClass( 'failure' ); + .removeAttr( 'class' ); + + time_element + .empty() + .hide(); $( '.info', state_element ) .removeClass( 'loader' ); - if( 0 !== rollback_element.size() ) + if( 'busy' === status ) { state_element - .addClass( 'failure' ) - .show(); + .addClass( 'indexing' ); - $( '.time', state_element ) - .text( rollback_element.text() ) - .timeago() - .show(); + if( autorefresh_status ) + { + $( '.info', state_element ) + .addClass( 'loader' ); + } - $( '.info strong', state_element ) - .text( $( 'str[name=""]', response ).text() ); + var time_elapsed_text = response.statusMessages['Time Elapsed']; + var elapsed_seconds = app.convert_duration_to_seconds( time_elapsed_text ); + time_elapsed_text = app.convert_seconds_to_readable_time( elapsed_seconds ); - $( '.info .details', state_element ) - .hide(); - - console.debug( 'rollback @ ', rollback_element.text() ); + var info_text = time_elapsed_text + ? 'Indexing since ' + time_elapsed_text + : 'Indexing ...'; + + show_full_info( info_text, elapsed_seconds ); + + if( !app.timeout && autorefresh_status ) + { + app.timeout = window.setTimeout + ( + function() + { + dataimport_fetch_status( true ) + }, + dataimport_timeout + ); + } + } + else if( rollback_time ) + { + state_element + .addClass( 'failure' ); + + set_time( rollback_time ); + + show_full_info(); + } + else if( abort_time ) + { + state_element + .addClass( 'aborted' ); + + set_time( abort_time ); + + show_full_info( 'Aborting current Import ...' ); } else if( 'idle' === status && 0 !== messages_count ) { state_element - .addClass( 'success' ) - .show(); + .addClass( 'success' ); - $( '.time', state_element ) - .text( started_at ) - .timeago() - .show(); - - $( '.info strong', state_element ) - .text( $( 'str[name=""]', response ).text() ); - - dataimport_compute_details( response, $( '.info .details', state_element ) ); - } - else if( 'busy' === status ) - { - state_element - .addClass( 'indexing' ) - .show(); - - $( '.time', state_element ) - .text( started_at ) - .timeago() - .show(); - - $( '.info', state_element ) - .addClass( 'loader' ); - - var indexing_text = 'Indexing ...'; - - var time_elapsed_text = $( 'str[name="Time Elapsed"]', response ).text(); - time_elapsed_text = convert_seconds_to_readable_time( convert_duration_to_seconds( time_elapsed_text ) ); - if( time_elapsed_text.length ) + var started_at = response.statusMessages['Full Dump Started']; + if( started_at ) { - indexing_text = 'Indexing since ' + time_elapsed_text + set_time( started_at ); } - $( '.info strong', state_element ) - .text( indexing_text ); - - dataimport_compute_details( response, $( '.info .details', state_element ) ); - - window.setTimeout( dataimport_fetch_status, 2000 ); + show_full_info(); } - else + else { - state_element.hide(); + state_element + .addClass( 'idle' ); + + show_info( 'No information available (idle)' ); } + + // show raw status + + var code = $( + '
' +
+                  app.format_json( xhr.responseText ).esc() +
+                  '
' + ); + + $( '#raw_output_container', content_element ).html( code ); + hljs.highlightBlock( code.get(0) ); }, error : function( xhr, text_status, error_thrown ) { @@ -489,24 +635,47 @@ sammy.get }, complete : function( xhr, text_status ) { + $( 'span', status_button ) + .removeClass( 'loader' ) + .addClass( 'success' ); + + window.setTimeout + ( + function() + { + $( 'span', status_button ) + .removeClass( 'success' ); + }, + dataimport_timeout / 2 + ); } } ); } - dataimport_fetch_status(); // form - $( 'form', form_element ) + var form = $( 'form', form_element ); + + form .ajaxForm ( { url : handler_url, - dataType : 'xml', + data : { + wt : 'json', + indent : 'true' + }, + dataType : 'json', + type: 'POST', beforeSend : function( xhr, settings ) { - $( 'form button', form_element ) + $( 'button[type="submit"] span', form_element ) .addClass( 'loader' ); + + error_element + .empty() + .hide(); }, beforeSubmit : function( array, form, options ) { @@ -545,22 +714,91 @@ sammy.get array.push( { name : tmp[0], value: tmp[1] } ); } } + + if( debug_mode ) + { + array.push( { name: 'dataConfig', value: $( '#dataimport_config .editable textarea' ).val() } ); + } }, success : function( response, text_status, xhr ) { - dataimport_fetch_status(); }, error : function( xhr, text_status, error_thrown ) { - console.debug( arguments ); + var response = null; + try + { + eval( 'response = ' + xhr.responseText + ';' ); + } + catch( e ){} + + error_element + .text( response.error.msg || 'Unknown Error (Exception w/o Message)' ) + .show(); }, complete : function( xhr, text_status ) { - $( 'form button', form_element ) + $( 'button[type="submit"] span', form_element ) .removeClass( 'loader' ); + + var debug = $( 'input[name="debug"]:checked', form ); + if( 0 !== debug.size() ) + { + var code = $( + '
' +
+                    app.format_json( xhr.responseText ).esc() +
+                    '
' + ); + + $( '.content', debug_response_element ).html( code ); + hljs.highlightBlock( code.get(0) ); + } + + dataimport_fetch_status(); } } ); + + $( 'input[name="debug"]', form ) + .off( 'change' ) + .on + ( + 'change', + function( event ) + { + debug_response_element.toggle( this.checked ); + } + ); + + $( '#auto-refresh-status a', form_element ) + .off( 'click' ) + .on + ( + 'click', + function( event ) + { + $.cookie( cookie_dataimport_autorefresh, $.cookie( cookie_dataimport_autorefresh ) ? null : true ); + $( this ).trigger( 'state' ); + + dataimport_fetch_status(); + + return false; + } + ) + .off( 'state' ) + .on + ( + 'state', + function( event ) + { + autorefresh_status = !!$.cookie( cookie_dataimport_autorefresh ); + + $.cookie( cookie_dataimport_autorefresh ) + ? $( this ).addClass( 'on' ) + : $( this ).removeClass( 'on' ); + } + ) + .trigger( 'state' ); } ); } diff --git a/solr/webapp/web/js/scripts/query.js b/solr/webapp/web/js/scripts/query.js index d30fa75165c..78b9f6f4202 100644 --- a/solr/webapp/web/js/scripts/query.js +++ b/solr/webapp/web/js/scripts/query.js @@ -56,7 +56,7 @@ sammy.get json : function( xhr ) { - return JSON.stringify( JSON.parse( xhr.responseText ), undefined, 2 ); + return app.format_json( xhr.responseText ); } }; diff --git a/solr/webapp/web/js/scripts/replication.js b/solr/webapp/web/js/scripts/replication.js index c962c391f65..b82683ec303 100644 --- a/solr/webapp/web/js/scripts/replication.js +++ b/solr/webapp/web/js/scripts/replication.js @@ -22,49 +22,6 @@ var core_basepath = null; var navigation_element = null; var replication_element = null; -var convert_duration_to_seconds = function( str ) -{ - var ret = 0; - var parts = new String( str ).split( ':' ).reverse(); - var parts_count = parts.length; - - for( var i = 0; i < parts_count; i++ ) - { - ret += parseInt( parts[i], 10 ) * Math.pow( 60, i ); - } - - return ret; -} - -var convert_seconds_to_readable_time = function( value ) -{ - var text = []; - value = parseInt( value ); - - var minutes = Math.floor( value / 60 ); - var hours = Math.floor( minutes / 60 ); - - if( 0 !== hours ) - { - text.push( hours + 'h' ); - value -= hours * 60 * 60; - minutes -= hours * 60; - } - - if( 0 !== minutes ) - { - text.push( minutes + 'm' ); - value -= minutes * 60; - } - - if( 0 !== value ) - { - text.push( value + 's' ); - } - - return text.join( ' ' ); -} - var init_timer = function( next_tick ) { if( timer_timeout ) @@ -83,7 +40,7 @@ var update_timer = function( next_tick ) } $( 'p .tick', timer_element ) - .text( convert_seconds_to_readable_time( next_tick ) ); + .text( app.convert_seconds_to_readable_time( next_tick ) ); timer_timeout = window.setTimeout ( @@ -151,7 +108,7 @@ var replication_fetch_status = function() var eta_element = $( '#eta', progress_element ); $( 'span', eta_element ) - .text( convert_seconds_to_readable_time( data.slave.timeRemaining ) ); + .text( app.convert_seconds_to_readable_time( data.slave.timeRemaining ) ); var bar_element = $( '#bar', progress_element ); $( '.files span', bar_element ) @@ -394,7 +351,7 @@ var replication_fetch_status = function() timer_element = $( '.timer', navigation_element ); approx_element = $( '.approx', timer_element ); - var next_tick = convert_duration_to_seconds( data.slave.pollInterval ); + var next_tick = app.convert_duration_to_seconds( data.slave.pollInterval ); approx_element.show(); if( data.slave.nextExecutionAt ) diff --git a/solr/webapp/web/tpl/dataimport.html b/solr/webapp/web/tpl/dataimport.html index e009e26e3b4..6fd9af12547 100644 --- a/solr/webapp/web/tpl/dataimport.html +++ b/solr/webapp/web/tpl/dataimport.html @@ -18,27 +18,46 @@ limitations under the License.
+
+
+
+ + +
-
+ + +
@@ -97,6 +144,11 @@ limitations under the License. Optimize + + @@ -106,17 +158,22 @@ limitations under the License. Start, Rows - - +
+ + +
- + + + +

Auto-Refresh Status