diff --git a/solr/src/webapp/web/css/screen.css b/solr/src/webapp/web/css/screen.css index 5fc779d2540..6e814655fde 100644 --- a/solr/src/webapp/web/css/screen.css +++ b/solr/src/webapp/web/css/screen.css @@ -402,7 +402,6 @@ ul #menu .config a { background-image: url( ../img/ico/gear.png ); } #menu .analysis a { background-image: url( ../img/ico/funnel.png ); } #menu .schema-browser a { background-image: url( ../img/ico/book-open-text.png ); } -#menu .stats a { background-image: url( ../img/ico/chart.png ); } #menu .replication a { background-image: url( ../img/ico/node.png ); } #menu .distribution a { background-image: url( ../img/ico/node-select.png ); } #menu .ping a { background-image: url( ../img/ico/system-monitor.png ); } @@ -439,6 +438,14 @@ ul padding-left: 21px; } +#content iframe +{ + border: 0; + display: block; + min-height: 400px; + width: 100%; +} + #content > pre { max-height: 600px; @@ -941,25 +948,62 @@ pre.syntax .tex .formula /* plugins */ -#content #plugins .loader +#content #plugins #navigation +{ + background-image: url( ../img/div.gif ); + background-position: 100% 0; + background-repeat: repeat-y; + width: 20%; +} + +#content #plugins #navigation a { background-position: 0 50%; + border-right: 1px solid #f0f0f0; + display: block; + margin-left: 1px; + padding: 3px 0; padding-left: 21px; } -#content #plugins .block h2 { background-image: url( ../img/ico/block-small.png ); } -#content #plugins #core h2 { background-image: url( ../img/ico/terminal.png ); } -#content #plugins #queryhandler h2 { background-image: url( ../img/ico/magnifier.png ); } -#content #plugins #updatehandler h2 { background-image: url( ../img/ico/arrow-circle.png ); } -#content #plugins #cache h2 { background-image: url( ../img/ico/disk-black.png ); } -#content #plugins #highlighting h2 { background-image: url( ../img/ico/highlighter-text.png ); } +#content #plugins #navigation .cache a { background-image: url( ../img/ico/disk-black.png ); } +#content #plugins #navigation .core a { background-image: url( ../img/ico/toolbox.png ); } +#content #plugins #navigation .other a { background-image: url( ../img/ico/zone.png ); } +#content #plugins #navigation .highlighting a { background-image: url( ../img/ico/highlighter-text.png ); } +#content #plugins #navigation .updatehandler a{ background-image: url( ../img/ico/arrow-circle.png ); } +#content #plugins #navigation .queryhandler a { background-image: url( ../img/ico/magnifier.png ); } -#content #plugins .block .entry +#content #plugins #navigation a:hover { - padding-top: 10px; + background-color: #fafafa; } -#content #plugins .block .entry a +#content #plugins #navigation .current a +{ + background-color: #fff; + border-right-color: #fff; + border-top: 1px solid #f0f0f0; + border-bottom: 1px solid #f0f0f0; + font-weight: bold; +} + +#content #plugins #frame +{ + float: right; + width: 78%; +} + +#content #plugins #frame .entry +{ + margin-bottom: 10px; +} + +#content #plugins #frame .entry:last-child +{ + margin-bottom: 0; +} + +#content #plugins #frame .entry a { background-image: url( ../img/ico/chevron-small-expand.png ); background-position: 0 50%; @@ -968,67 +1012,67 @@ pre.syntax .tex .formula padding-left: 21px; } -#content #plugins .block .entry.expanded a +#content #plugins #frame .entry.expanded a { background-image: url( ../img/ico/chevron-small.png ); } -#content #plugins .block .entry.expanded ul +#content #plugins #frame .entry.expanded ul { display: block; } -#content #plugins .block .entry ul +#content #plugins #frame .entry ul { display: none; padding-top: 5px; margin-left: 21px; } -#content #plugins .block .entry li +#content #plugins #frame .entry li { padding-top: 2px; padding-bottom: 2px; } -#content #plugins .block .entry li.stats +#content #plugins #frame .entry li.stats { border-top: 1px solid #c0c0c0; margin-top: 5px; padding-top: 5px; } -#content #plugins .block .entry li.odd +#content #plugins #frame .entry li.odd { background-color: #f8f8f8; } -#content #plugins .block .entry dt, -#content #plugins .block .entry .stats span +#content #plugins #frame .entry dt, +#content #plugins #frame .entry .stats span { float: left; width: 11%; } -#content #plugins .block .entry dd, -#content #plugins .block .entry .stats ul +#content #plugins #frame .entry dd, +#content #plugins #frame .entry .stats ul { float: right; width: 88%; } -#content #plugins .block .entry .stats ul +#content #plugins #frame .entry .stats ul { margin: 0; padding: 0; } -#content #plugins .block .entry .stats dt +#content #plugins #frame .entry .stats dt { width: 27%; } -#content #plugins .block .entry .stats dd +#content #plugins #frame .entry .stats dd { width: 72%; } @@ -2102,6 +2146,29 @@ pre.syntax .tex .formula display: none; } +#content #threads .controls +{ + padding-top: 5px; + padding-bottom: 5px; +} + +#content #threads .controls a +{ + background-image: url( ../img/ico/chevron-small-expand.png ); + padding-left: 21px; +} + +#content #threads.expanded .controls a +{ + background-image: url( ../img/ico/chevron-small.png ); +} + +#content #threads.expanded .controls .expand, +#content #threads.collapsed .controls .collapse +{ + display: none; +} + /* dataimport */ #content #dataimport diff --git a/solr/src/webapp/web/img/ico/system-monitor--exclamation.png b/solr/src/webapp/web/img/ico/system-monitor--exclamation.png new file mode 100644 index 00000000000..c6f6a5f646b Binary files /dev/null and b/solr/src/webapp/web/img/ico/system-monitor--exclamation.png differ diff --git a/solr/src/webapp/web/img/ico/toolbox.png b/solr/src/webapp/web/img/ico/toolbox.png new file mode 100644 index 00000000000..b581d7794d4 Binary files /dev/null and b/solr/src/webapp/web/img/ico/toolbox.png differ diff --git a/solr/src/webapp/web/img/ico/zone.png b/solr/src/webapp/web/img/ico/zone.png new file mode 100644 index 00000000000..80fc7be9e03 Binary files /dev/null and b/solr/src/webapp/web/img/ico/zone.png differ diff --git a/solr/src/webapp/web/index.jsp b/solr/src/webapp/web/index.jsp index a632b365327..1a50a8a6302 100644 --- a/solr/src/webapp/web/index.jsp +++ b/solr/src/webapp/web/index.jsp @@ -21,6 +21,8 @@ app_config.solr_path = '<%= request.getContextPath() %>'; app_config.core_admin_path = '<%= cores.getAdminPath() %>'; app_config.zookeeper_path = 'zookeeper.jsp'; + app_config.schema_path = '/admin/file?file=schema.xml&contentType=text/xml;charset=utf-8'; + app_config.config_path = '/admin/file?file=solrconfig.xml&contentType=text/xml;charset=utf-8'; diff --git a/solr/src/webapp/web/js/script.js b/solr/src/webapp/web/js/script.js index acc697ed2c1..d98605684bc 100644 --- a/solr/src/webapp/web/js/script.js +++ b/solr/src/webapp/web/js/script.js @@ -39,7 +39,7 @@ var sammy = $.sammy $.ajax ( { - url : $( this.params.element ).attr( 'href' ) + '?wt=json', + url : $( this.params.element ).attr( 'rel' ) + '?wt=json&ts=' + (new Date).getTime(), dataType : 'json', context: this.params.element, beforeSend : function( arr, form, options ) @@ -883,7 +883,7 @@ var sammy = $.sammy if( -1 !== key.indexOf( '.path' ) ) { - displayed_value = system_properties[key].split( ':' ); + displayed_value = system_properties[key].split( system_properties['path.separator'] ); if( 1 < displayed_value.length ) { item_class += ' multi'; @@ -958,6 +958,8 @@ var sammy = $.sammy }, success : function( response, text_status, xhr ) { + var self = this; + var threadDumpData = response.system.threadDump; var threadDumpContent = []; var c = 0; @@ -966,23 +968,23 @@ var sammy = $.sammy var state = threadDumpData[i].state; var name = '' + threadDumpData[i].name + ''; - var class = [state]; + var classes = [state]; var details = ''; if( 0 !== c % 2 ) { - class.push( 'odd' ); + classes.push( 'odd' ); } if( threadDumpData[i].lock ) { - class.push( 'lock' ); + classes.push( 'lock' ); name += "\n" + '

' + threadDumpData[i].lock + '

'; } if( threadDumpData[i].stackTrace && 0 !== threadDumpData[i].stackTrace.length ) { - class.push( 'stacktrace' ); + classes.push( 'stacktrace' ); var stack_trace = threadDumpData[i].stackTrace .join( '
  • ' ) @@ -995,7 +997,7 @@ var sammy = $.sammy + ''; } - var item = '' + "\n" + var item = '' + "\n" + '' + state +'' + "\n" + '' + threadDumpData[i].id + '' + "\n" @@ -1024,7 +1026,42 @@ var sammy = $.sammy $( this ).closest( 'tr' ) .toggleClass( 'open' ); } - ) + ); + + $( '.controls a', this ) + .die( 'click' ) + .live + ( + 'click', + function( event ) + { + var threads_element = $( self ); + var is_collapsed = threads_element.hasClass( 'collapsed' ); + var thread_rows = $( 'tr', threads_element ); + + thread_rows + .each + ( + function( index, element ) + { + if( is_collapsed ) + { + $( element ) + .addClass( 'open' ); + } + else + { + $( element ) + .removeClass( 'open' ); + } + } + ); + + threads_element + .toggleClass( 'collapsed' ) + .toggleClass( 'expanded' ); + } + ); }, error : function( xhr, text_status, error_thrown) { @@ -1425,8 +1462,6 @@ var sammy = $.sammy }, error : function( xhr, text_status, error_thrown ) { - console.debug( arguments ); - $( '#content' ) .html( 'sorry, no replication-handler defined!' ); }, @@ -2512,8 +2547,8 @@ var sammy = $.sammy var dataimport_handlers = []; for( var key in handlers ) { - if( handlers[key].class !== key && - handlers[key].class === 'org.apache.solr.handler.dataimport.DataImportHandler' ) + if( handlers[key]['class'] !== key && + handlers[key]['class'] === 'org.apache.solr.handler.dataimport.DataImportHandler' ) { dataimport_handlers.push( key ); } @@ -2944,47 +2979,40 @@ var sammy = $.sammy } ); - // #/:core/info(/stats) - this.get + + + this.bind ( - /^#\/([\w\d]+)\/info/, - function( context ) + 'plugins_load', + function( event, params ) { - var core_basepath = this.active_core.attr( 'data-basepath' ); - var content_element = $( '#content' ); - var show_stats = 0 <= this.path.indexOf( 'stats' ); - - if( show_stats ) + var callback = function() { - $( 'li.stats', this.active_core ) - .addClass( 'active' ); - } - else - { - $( 'li.plugins', this.active_core ) - .addClass( 'active' ); + params.callback( app.plugin_data.plugin_data, app.plugin_data.sort_table, app.plugin_data.types ); } - content_element - .html( '
    ' ); - + if( app.plugin_data ) + { + callback( app.plugin_data ); + return true; + } + + var core_basepath = params.active_core.attr( 'data-basepath' ); $.ajax ( { url : core_basepath + '/admin/mbeans?stats=true&wt=json', dataType : 'json', - context : $( '#plugins', content_element ), beforeSend : function( xhr, settings ) { - this - .html( '
    Loading ...
    ' ); }, success : function( response, text_status, xhr ) { + var types = []; var sort_table = {}; - var content = ''; - - response.plugins = {}; + var plugin_data = {}; + + var types_obj = {}; var plugin_key = null; for( var i = 0; i < response['solr-mbeans'].length; i++ ) @@ -2995,140 +3023,60 @@ var sammy = $.sammy } else { - response.plugins[plugin_key] = response['solr-mbeans'][i]; + plugin_data[plugin_key] = response['solr-mbeans'][i]; } } - for( var key in response.plugins ) + for( var key in plugin_data ) { sort_table[key] = { url : [], component : [], handler : [] }; - for( var part_key in response.plugins[key] ) + for( var part_key in plugin_data[key] ) { if( 0 < part_key.indexOf( '.' ) ) { + types_obj[key] = true; sort_table[key]['handler'].push( part_key ); } else if( 0 === part_key.indexOf( '/' ) ) { + types_obj[key] = true; sort_table[key]['url'].push( part_key ); } else { + types_obj[key] = true; sort_table[key]['component'].push( part_key ); } } - - content += '
    ' + "\n"; - content += '

    ' + key + '

    ' + "\n"; - content += '
    ' + "\n"; - content += '
      '; - - for( var sort_key in sort_table[key] ) - { - sort_table[key][sort_key].sort(); - var sort_key_length = sort_table[key][sort_key].length; - - for( var i = 0; i < sort_key_length; i++ ) - { - content += '
    • ' + sort_table[key][sort_key][i] + '' + "\n"; - content += '
        ' + "\n"; - - var details = response.plugins[key][ sort_table[key][sort_key][i] ]; - for( var detail_key in details ) - { - if( 'stats' !== detail_key ) - { - var detail_value = details[detail_key]; - - if( 'description' === detail_key ) - { - detail_value = detail_value.replace( /,/g, ',​' ); - } - else if( 'src' === detail_key ) - { - detail_value = detail_value.replace( /\//g, '/​' ); - } - - content += '
      • ' + "\n"; - content += '
        ' + detail_key + ':
        ' + "\n"; - content += '
        ' + detail_value + '
        ' + "\n"; - content += '
      • ' + "\n"; - } - else if( 'stats' === detail_key && details[detail_key] && show_stats ) - { - content += '
      • ' + "\n"; - content += '' + detail_key + ':' + "\n"; - content += '
          ' + "\n"; - - for( var stats_key in details[detail_key] ) - { - var stats_value = details[detail_key][stats_key]; - - if( 'readerDir' === stats_key ) - { - stats_value = stats_value.replace( /@/g, '@​' ); - } - - content += '
        • ' + "\n"; - content += '
          ' + stats_key + ':
          ' + "\n"; - content += '
          ' + stats_value + '
          ' + "\n"; - content += '
        • ' + "\n"; - } - - content += '
      • ' + "\n"; - } - } - - content += '
      ' + "\n"; - } - } - - content += '
    ' + "\n"; - content += '
    ' + "\n"; - content += '
    ' + "\n"; } - - this - .html( content ); - - $( '.block a', this ) - .die( 'click' ) - .live - ( - 'click', - function( event ) - { - $( this ).parent() - .toggleClass( 'expanded' ); - } - ); - - $( '.block .content > ul:empty', this ) - .each - ( - function( index, element ) - { - $( element ).parents( '.block' ) - .hide(); - } - ); - - $( '.entry', this ) - .each - ( - function( i, entry ) - { - $( '.detail > li', entry ).not( '.stats' ).filter( ':even' ) - .addClass( 'odd' ); - $( '.stats li:odd', entry ) - .addClass( 'odd' ); - } - ); + for( var type in types_obj ) + { + types.push( type ); + } + types.sort(); + + app.plugin_data = { + 'plugin_data' : plugin_data, + 'sort_table' : sort_table, + 'types' : types + } + + $.get + ( + 'tpl/plugins.html', + function( template ) + { + $( '#content' ) + .html( template ); + + callback( app.plugin_data ); + } + ); }, error : function( xhr, text_status, error_thrown) { @@ -3138,22 +3086,170 @@ var sammy = $.sammy } } ); - + } + ); + + // #/:core/plugins/$type + this.get + ( + /^#\/([\w\d]+)\/(plugins)\/(\w+)$/, + function( context ) + { + var content_element = $( '#content' ); + var type = context.params.splat[2].toUpperCase(); + var context_path = context.path.split( '?' ).shift(); + + sammy.trigger + ( + 'plugins_load', + { + active_core : this.active_core, + callback : function( plugin_data, plugin_sort, types ) + { + var frame_element = $( '#frame', content_element ); + var navigation_element = $( '#navigation ul', content_element ); + + var navigation_content = []; + for( var i = 0; i < types.length; i++ ) + { + var type_url = context.params.splat[0] + '/' + + context.params.splat[1] + '/' + + types[i].toLowerCase(); + + navigation_content.push + ( + '
  • ' + + '' + types[i] + '' + + '
  • ' + ); + } + + navigation_element + .html( navigation_content.join( "\n" ) ); + + $( 'a[href="' + context_path + '"]', navigation_element ) + .parent().addClass( 'current' ); + + var content = '' + "\n"; + + frame_element + .html( content ); + + $( 'a[href="' + decodeURIComponent( context.path ) + '"]', frame_element ) + .parent().addClass( 'expanded' ); + + $( '.entry', frame_element ) + .each + ( + function( i, entry ) + { + $( '.detail > li', entry ).not( '.stats' ).filter( ':even' ) + .addClass( 'odd' ); + + $( '.stats li:odd', entry ) + .addClass( 'odd' ); + } + ); + } + } + ); + } + ); + + // #/:core/plugins + this.get + ( + /^#\/([\w\d]+)\/(plugins)$/, + function( context ) + { + delete app.plugin_data; + + sammy.trigger + ( + 'plugins_load', + { + active_core : this.active_core, + callback : function( plugin_data, plugin_sort, types ) + { + context.redirect( context.path + '/' + types[0].toLowerCase() ); + } + } + ); } ); // #/:core/query this.get ( - /^#\/([\w\d]+)\/query$/, + /^#\/([\w\d]+)\/(query)$/, function( context ) { var core_basepath = this.active_core.attr( 'data-basepath' ); var content_element = $( '#content' ); - $( 'li.query', this.active_core ) - .addClass( 'active' ); - $.get ( 'tpl/query.html', @@ -3228,6 +3324,15 @@ var sammy = $.sammy } ) + for( var key in context.params ) + { + if( 'string' === typeof context.params[key] ) + { + $( '[name="' + key + '"]', query_form ) + .val( context.params[key] ); + } + } + query_form .die( 'submit' ) .live @@ -3235,11 +3340,33 @@ var sammy = $.sammy 'submit', function( event ) { + var form_map = {}; + var form_values = []; + var all_form_values = query_form.formToArray(); + + for( var i = 0; i < all_form_values.length; i++ ) + { + if( !all_form_values[i].value || 0 === all_form_values[i].value.length ) + { + continue; + } + + var name_parts = all_form_values[i].name.split( '.' ); + if( 1 < name_parts.length && !form_map[name_parts[0]] ) + { + console.debug( 'skip "' + all_form_values[i].name + '", parent missing' ); + continue; + } + + form_map[all_form_values[i].name] = all_form_values[i].value; + form_values.push( all_form_values[i] ); + } + var query_url = window.location.protocol + '//' + window.location.host + core_basepath + '/select?' + - query_form.formSerialize(); + $.param( form_values ); url_element .val( query_url ) @@ -3524,10 +3651,12 @@ var sammy = $.sammy /^#\/([\w\d]+)\/(schema|config)$/, function( context ) { + var core_basepath = this.active_core.attr( 'data-basepath' ); + $.ajax ( { - url : $( '.active a', this.active_core ).attr( 'href' ), + url : core_basepath + app.config[context.params.splat[1] + '_path'], dataType : 'xml', context : $( '#content' ), beforeSend : function( xhr, settings ) @@ -3993,22 +4122,41 @@ var sammy = $.sammy { this .html( template ); - - var memory_data = {}; - if( app.dashboard_values['jvm']['memory']['raw'] ) + + var jvm_memory = $.extend + ( + { + 'free' : null, + 'total' : null, + 'max' : null, + 'used' : null, + 'raw' : { + 'free' : null, + 'total' : null, + 'max' : null, + 'used' : null, + 'used%' : null + } + }, + app.dashboard_values['jvm']['memory'] + ); + + var parse_memory_value = function( value ) { - var jvm_memory = app.dashboard_values['jvm']['memory']['raw']; - memory_data['memory-bar-max'] = parseInt( jvm_memory['max'] ); - memory_data['memory-bar-total'] = parseInt( jvm_memory['total'] ); - memory_data['memory-bar-used'] = parseInt( jvm_memory['used'] ); - } - else - { - var jvm_memory = app.dashboard_values['jvm']['memory']; - memory_data['memory-bar-max'] = parseFloat( jvm_memory['max'] ) * 1024 * 1024; - memory_data['memory-bar-total'] = parseFloat( jvm_memory['total'] ) * 1024 * 1024; - memory_data['memory-bar-used'] = parseFloat( jvm_memory['used'] ) * 1024 * 1024; - } + if( value !== Number( value ) ) + { + var units = 'BKMGTPEZY'; + var match = value.match( /^(\d+([,\.]\d+)?) (\w)\w?$/ ); + var value = parseFloat( match[1] ) * Math.pow( 1024, units.indexOf( match[3].toUpperCase() ) ); + } + + return value; + }; + var memory_data = { + 'memory-bar-max' : parse_memory_value( jvm_memory['raw']['max'] || jvm_memory['max'] ), + 'memory-bar-total' : parse_memory_value( jvm_memory['raw']['total'] || jvm_memory['total'] ), + 'memory-bar-used' : parse_memory_value( jvm_memory['raw']['used'] || jvm_memory['used'] ) + }; for( var key in memory_data ) { @@ -4148,6 +4296,8 @@ var solr_admin = function( app_config ) params = null, dashboard_values = null, schema_browser_data = null, + + plugin_data = null, this.init_menu = function() { @@ -4165,17 +4315,6 @@ var solr_admin = function( app_config ) return false; } ); - - $( 'a[rel]', menu_element ) - .live - ( - 'click', - function() - { - location.href = this.rel; - return false; - } - ); } this.init_cores = function() @@ -4230,16 +4369,15 @@ var solr_admin = function( app_config ) + '

    ' + core_name + '

    ' + "\n" + ' ' + "\n" + ''; diff --git a/solr/src/webapp/web/tpl/analysis.html b/solr/src/webapp/web/tpl/analysis.html index 8f250a55b71..c801326feac 100644 --- a/solr/src/webapp/web/tpl/analysis.html +++ b/solr/src/webapp/web/tpl/analysis.html @@ -58,7 +58,7 @@

    {headline}
    - Verbose Output + Verbose Output

    diff --git a/solr/src/webapp/web/tpl/plugins.html b/solr/src/webapp/web/tpl/plugins.html new file mode 100644 index 00000000000..abae378b35b --- /dev/null +++ b/solr/src/webapp/web/tpl/plugins.html @@ -0,0 +1,14 @@ +
    + +
    + +
    + + + +
    diff --git a/solr/src/webapp/web/tpl/query.html b/solr/src/webapp/web/tpl/query.html index 828b6da853b..7e036148777 100644 --- a/solr/src/webapp/web/tpl/query.html +++ b/solr/src/webapp/web/tpl/query.html @@ -33,7 +33,7 @@ - +