mirror of https://github.com/apache/lucene.git
712 lines
20 KiB
JavaScript
712 lines
20 KiB
JavaScript
/*
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
var solrAdminApp = angular.module("solrAdminApp", [
|
|
"ngResource",
|
|
"ngRoute",
|
|
"ngCookies",
|
|
"ngtimeago",
|
|
"solrAdminServices",
|
|
"localytics.directives"
|
|
]);
|
|
|
|
solrAdminApp.config([
|
|
'$routeProvider', function($routeProvider) {
|
|
$routeProvider.
|
|
when('/', {
|
|
templateUrl: 'partials/index.html',
|
|
controller: 'IndexController'
|
|
}).
|
|
when('/~logging', {
|
|
templateUrl: 'partials/logging.html',
|
|
controller: 'LoggingController'
|
|
}).
|
|
when('/~logging/level', {
|
|
templateUrl: 'partials/logging-levels.html',
|
|
controller: 'LoggingLevelController'
|
|
}).
|
|
when('/~cloud', {
|
|
templateUrl: 'partials/cloud.html',
|
|
controller: 'CloudController'
|
|
}).
|
|
when('/~cores', {
|
|
templateUrl: 'partials/cores.html',
|
|
controller: 'CoreAdminController'
|
|
}).
|
|
when('/~cores/:core', {
|
|
templateUrl: 'partials/cores.html',
|
|
controller: 'CoreAdminController'
|
|
}).
|
|
when('/~threads', {
|
|
templateUrl: 'partials/threads.html',
|
|
controller: 'ThreadsController'
|
|
}).
|
|
when('/~java-properties', {
|
|
templateUrl: 'partials/java-properties.html',
|
|
controller: 'JavaPropertiesController'
|
|
}).
|
|
when('/:core', {
|
|
templateUrl: 'partials/core_overview.html',
|
|
controller: 'CoreOverviewController'
|
|
}).
|
|
when('/:core/analysis', {
|
|
templateUrl: 'partials/analysis.html',
|
|
controller: 'AnalysisController'
|
|
}).
|
|
when('/:core/dataimport', {
|
|
templateUrl: 'partials/dataimport.html',
|
|
controller: 'DataImportController'
|
|
}).
|
|
when('/:core/dataimport/:handler*', {
|
|
templateUrl: 'partials/dataimport.html',
|
|
controller: 'DataImportController'
|
|
}).
|
|
when('/:core/documents', {
|
|
templateUrl: 'partials/documents.html',
|
|
controller: 'DocumentsController'
|
|
}).
|
|
when('/:core/files', {
|
|
templateUrl: 'partials/files.html',
|
|
controller: 'FilesController'
|
|
}).
|
|
when('/:core/plugins', {
|
|
templateUrl: 'partials/plugins.html',
|
|
controller: 'PluginsController',
|
|
reloadOnSearch: false
|
|
}).
|
|
when('/:core/plugins/:legacytype', {
|
|
templateUrl: 'partials/plugins.html',
|
|
controller: 'PluginsController',
|
|
reloadOnSearch: false
|
|
}).
|
|
when('/:core/query', {
|
|
templateUrl: 'partials/query.html',
|
|
controller: 'QueryController'
|
|
}).
|
|
when('/:core/replication', {
|
|
templateUrl: 'partials/replication.html',
|
|
controller: 'ReplicationController'
|
|
}).
|
|
when('/:core/dataimport', {
|
|
templateUrl: 'partials/dataimport.html',
|
|
controller: 'DataImportController'
|
|
}).
|
|
when('/:core/dataimport/:handler*', {
|
|
templateUrl: 'partials/dataimport.html',
|
|
controller: 'DataImportController'
|
|
}).
|
|
when('/:core/schema-browser', {
|
|
templateUrl: 'partials/schema-browser.html',
|
|
controller: 'SchemaBrowserController'
|
|
}).
|
|
when('/:core/segments', {
|
|
templateUrl: 'partials/segments.html',
|
|
controller: 'SegmentsController'
|
|
}).
|
|
otherwise({
|
|
redirectTo: '/'
|
|
});
|
|
}])
|
|
.filter('highlight', function($sce) {
|
|
return function(input, lang) {
|
|
if (lang && input && lang!="text") return hljs.highlight(lang, input).value;
|
|
return input;
|
|
}
|
|
})
|
|
.filter('unsafe', function($sce) { return $sce.trustAsHtml; })
|
|
.directive('loadingStatusMessage', function() {
|
|
return {
|
|
link: function($scope, $element, attrs) {
|
|
var show = function() {$element.css('display', 'block')};
|
|
var hide = function() {$element.css('display', 'none')};
|
|
$scope.$on('loadingStatusActive', show);
|
|
$scope.$on('loadingStatusInactive', hide);
|
|
}
|
|
};
|
|
})
|
|
.filter('readableSeconds', function() {
|
|
return function(input) {
|
|
seconds = parseInt(input||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(' ');
|
|
};
|
|
})
|
|
.filter('number', function($locale) {
|
|
return function(input) {
|
|
var sep = {
|
|
'de_CH' : '\'',
|
|
'de' : '.',
|
|
'en' : ',',
|
|
'es' : '.',
|
|
'it' : '.',
|
|
'ja' : ',',
|
|
'sv' : ' ',
|
|
'tr' : '.',
|
|
'_' : '' // fallback
|
|
};
|
|
|
|
var browser = {};
|
|
var match = $locale.id.match( /^(\w{2})([-_](\w{2}))?$/ );
|
|
if (match[1]) {
|
|
browser.language = match[1].toLowerCase();
|
|
}
|
|
if (match[1] && match[3]) {
|
|
browser.locale = match[1] + '_' + match[3];
|
|
}
|
|
|
|
var result= ( input || 0 ).toString().replace(/\B(?=(\d{3})+(?!\d))/g,
|
|
sep[ browser.locale ] || sep[ browser.language ] || sep['_']);
|
|
console.log(result);
|
|
return result;
|
|
};
|
|
})
|
|
.filter('orderObjectBy', function() {
|
|
return function(items, field, reverse) {
|
|
var filtered = [];
|
|
angular.forEach(items, function(item) {
|
|
filtered.push(item);
|
|
});
|
|
filtered.sort(function (a, b) {
|
|
return (a[field] > b[field] ? 1 : -1);
|
|
});
|
|
if(reverse) filtered.reverse();
|
|
return filtered;
|
|
};
|
|
})
|
|
.directive('jstree', function($parse) {
|
|
return {
|
|
restrict: 'EA',
|
|
scope: {
|
|
data: '=',
|
|
onSelect: '&'
|
|
},
|
|
link: function(scope, element, attrs) {
|
|
scope.$watch("data", function(newValue, oldValue) {
|
|
if (newValue) {
|
|
var treeConfig = {
|
|
"plugins" : [ "themes", "json_data", "ui" ],
|
|
"json_data" : {
|
|
"data" : scope.data,
|
|
"progressive_render" : true
|
|
},
|
|
"core" : {
|
|
"animation" : 0
|
|
}
|
|
};
|
|
|
|
var tree = $(element).jstree(treeConfig);
|
|
tree.jstree('open_node','li:first');
|
|
if (tree) {
|
|
element.bind("select_node.jstree", function (event, data) {
|
|
scope.$apply(function() {
|
|
scope.onSelect({url: data.args[0].href, data: data});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}, true);
|
|
}
|
|
};
|
|
})
|
|
.directive('connectionMessage', function() {
|
|
return {
|
|
link: function($scope, $element, attrs) {
|
|
var show = function() {$element.css('display', 'block')};
|
|
var hide = function() {$element.css('display', 'none')};
|
|
$scope.$on('connectionStatusActive', show);
|
|
$scope.$on('connectionStatusInactive', hide);
|
|
}
|
|
};
|
|
})
|
|
.factory('httpInterceptor', function($q, $rootScope, $timeout, $injector) {
|
|
var activeRequests = 0;
|
|
|
|
var started = function(config) {
|
|
if (activeRequests == 0) {
|
|
$rootScope.$broadcast('loadingStatusActive');
|
|
}
|
|
activeRequests++;
|
|
config.timeout = 10000;
|
|
return config || $q.when(config);
|
|
};
|
|
|
|
var ended = function(response) {
|
|
activeRequests--;
|
|
if (activeRequests == 0) {
|
|
$rootScope.$broadcast('loadingStatusInactive');
|
|
}
|
|
if ($rootScope.retryCount>0) {
|
|
$rootScope.connectionRecovered = true;
|
|
$rootScope.retryCount=0;
|
|
$timeout(function() {
|
|
$rootScope.connectionRecovered=false;
|
|
$rootScope.$broadcast('connectionStatusInactive');
|
|
},2000);
|
|
}
|
|
return response || $q.when(response);
|
|
};
|
|
|
|
var failed = function(rejection) {
|
|
activeRequests--;
|
|
if (activeRequests == 0) {
|
|
$rootScope.$broadcast('loadingStatusInactive');
|
|
}
|
|
if (rejection.config.params.doNotIntercept) {
|
|
return rejection;
|
|
}
|
|
if (rejection.status === 0) {
|
|
$rootScope.$broadcast('connectionStatusActive');
|
|
if (!$rootScope.retryCount) $rootScope.retryCount=0;
|
|
$rootScope.retryCount ++;
|
|
var $http = $injector.get('$http');
|
|
var result = $http(rejection.config);
|
|
return result;
|
|
} else {
|
|
$rootScope.exception = rejection;
|
|
}
|
|
return $q.reject(rejection);
|
|
}
|
|
|
|
return {request: started, response: ended, responseError: failed};
|
|
})
|
|
.config(function($httpProvider) {
|
|
$httpProvider.interceptors.push("httpInterceptor");
|
|
})
|
|
.directive('fileModel', function ($parse) {
|
|
return {
|
|
restrict: 'A',
|
|
link: function(scope, element, attrs) {
|
|
var model = $parse(attrs.fileModel);
|
|
var modelSetter = model.assign;
|
|
|
|
element.bind('change', function(){
|
|
scope.$apply(function(){
|
|
modelSetter(scope, element[0].files[0]);
|
|
});
|
|
});
|
|
}
|
|
};
|
|
});
|
|
|
|
solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $location, Cores, System, Ping) {
|
|
$rootScope.hideException = function() {delete $rootScope.exception};
|
|
$scope.refresh = function() {
|
|
Cores.list(function(data) {
|
|
$scope.cores = [];
|
|
var currentCoreName = $route.current.params.core;
|
|
for (key in data.status) {
|
|
var core = data.status[key];
|
|
$scope.cores.push(core);
|
|
if (core.name == currentCoreName) {
|
|
$scope.currentCore = core;
|
|
}
|
|
}
|
|
});
|
|
System.get(function(data) {
|
|
$scope.isCloudEnabled = data.mode.match( /solrcloud/i )
|
|
});
|
|
};
|
|
$scope.refresh();
|
|
|
|
$scope.resetMenu = function(page) {
|
|
$scope.showingLogging = page.lastIndexOf("logging", 0) === 0;
|
|
$scope.showingCloud = page.lastIndexOf("cloud", 0) === 0;
|
|
$scope.page = page;
|
|
};
|
|
|
|
$scope.ping = function() {
|
|
Ping.ping({core: $scope.currentCore.name}, function(data) {
|
|
$scope.pingMS = data.responseHeader.QTime;
|
|
});
|
|
// @todo .attr( 'title', '/admin/ping is not configured (' + xhr.status + ': ' + error_thrown + ')' );
|
|
};
|
|
|
|
$scope.dumpCloud = function() {
|
|
$scope.$broadcast("cloud-dump");
|
|
}
|
|
});
|
|
|
|
|
|
|
|
(function(window, angular, undefined) {
|
|
'use strict';
|
|
|
|
angular.module('ngClipboard', []).
|
|
provider('ngClip', function() {
|
|
var self = this;
|
|
this.path = '//cdnjs.cloudflare.com/ajax/libs/zeroclipboard/2.1.6/ZeroClipboard.swf';
|
|
return {
|
|
setPath: function(newPath) {
|
|
self.path = newPath;
|
|
},
|
|
setConfig: function(config) {
|
|
self.config = config;
|
|
},
|
|
$get: function() {
|
|
return {
|
|
path: self.path,
|
|
config: self.config
|
|
};
|
|
}
|
|
};
|
|
}).
|
|
run(['ngClip', function(ngClip) {
|
|
var config = {
|
|
swfPath: ngClip.path,
|
|
trustedDomains: ["*"],
|
|
allowScriptAccess: "always",
|
|
forceHandCursor: true,
|
|
};
|
|
ZeroClipboard.config(angular.extend(config,ngClip.config || {}));
|
|
}]).
|
|
directive('clipCopy', ['ngClip', function (ngClip) {
|
|
return {
|
|
scope: {
|
|
clipCopy: '&',
|
|
clipClick: '&',
|
|
clipClickFallback: '&'
|
|
},
|
|
restrict: 'A',
|
|
link: function (scope, element, attrs) {
|
|
// Bind a fallback function if flash is unavailable
|
|
if (ZeroClipboard.isFlashUnusable()) {
|
|
element.bind('click', function($event) {
|
|
// Execute the expression with local variables `$event` and `copy`
|
|
scope.$apply(scope.clipClickFallback({
|
|
$event: $event,
|
|
copy: scope.$eval(scope.clipCopy)
|
|
}));
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// Create the client object
|
|
var client = new ZeroClipboard(element);
|
|
if (attrs.clipCopy === "") {
|
|
scope.clipCopy = function(scope) {
|
|
return element[0].previousElementSibling.innerText;
|
|
};
|
|
}
|
|
client.on( 'ready', function(readyEvent) {
|
|
|
|
client.on('copy', function (event) {
|
|
var clipboard = event.clipboardData;
|
|
clipboard.setData(attrs.clipCopyMimeType || 'text/plain', scope.$eval(scope.clipCopy));
|
|
});
|
|
|
|
client.on( 'aftercopy', function(event) {
|
|
if (angular.isDefined(attrs.clipClick)) {
|
|
scope.$apply(scope.clipClick);
|
|
}
|
|
});
|
|
|
|
scope.$on('$destroy', function() {
|
|
client.destroy();
|
|
});
|
|
});
|
|
}
|
|
};
|
|
}]);
|
|
})(window, window.angular);
|
|
|
|
|
|
/* THE BELOW CODE IS TAKEN FROM js/scripts/app.js, AND STILL REQUIRES INTEGRATING
|
|
|
|
|
|
// @todo clear timeouts
|
|
|
|
// activate_core
|
|
this.before
|
|
(
|
|
{},
|
|
function( context )
|
|
{
|
|
|
|
var menu_wrapper = $( '#menu-wrapper' );
|
|
|
|
// global dashboard doesn't have params.splat
|
|
if( !this.params.splat )
|
|
{
|
|
this.params.splat = [ '~index' ];
|
|
}
|
|
|
|
var selector = '~' === this.params.splat[0][0]
|
|
? '#' + this.params.splat[0].replace( /^~/, '' ) + '.global'
|
|
: '#core-selector #' + this.params.splat[0].replace( /\./g, '__' );
|
|
|
|
var active_element = $( selector, menu_wrapper );
|
|
|
|
// @todo "There is no core with this name"
|
|
|
|
if( active_element.hasClass( 'global' ) )
|
|
{
|
|
active_element
|
|
.addClass( 'active' );
|
|
|
|
if( this.params.splat[1] )
|
|
{
|
|
$( '.' + this.params.splat[1], active_element )
|
|
.addClass( 'active' );
|
|
}
|
|
|
|
$( '#core-selector option[selected]' )
|
|
.removeAttr( 'selected' )
|
|
.trigger( 'liszt:updated' );
|
|
|
|
$( '#core-selector .chzn-container > a' )
|
|
.addClass( 'chzn-default' );
|
|
}
|
|
else
|
|
{
|
|
active_element
|
|
.attr( 'selected', 'selected' )
|
|
.trigger( 'liszt:updated' );
|
|
|
|
|
|
$( '#core-menu .' + this.params.splat[1] )
|
|
.addClass( 'active' );
|
|
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
var solr_admin = function( app_config )
|
|
{
|
|
this.menu_element = $( '#core-selector select' );
|
|
this.core_menu = $( '#core-menu ul' );
|
|
|
|
this.config = config;
|
|
this.timeout = null;
|
|
|
|
this.core_regex_base = '^#\\/([\\w\\d-\\.]+)';
|
|
|
|
show_global_error = function( error )
|
|
{
|
|
var main = $( '#main' );
|
|
|
|
$( 'div[id$="-wrapper"]', main )
|
|
.remove();
|
|
|
|
main
|
|
.addClass( 'error' )
|
|
.append( error );
|
|
|
|
var pre_tags = $( 'pre', main );
|
|
if( 0 !== pre_tags.size() )
|
|
{
|
|
hljs.highlightBlock( pre_tags.get(0) );
|
|
}
|
|
};
|
|
|
|
sort_cores_data = function sort_cores_data( cores_status )
|
|
{
|
|
// build array of core-names for sorting
|
|
var core_names = [];
|
|
for( var core_name in cores_status )
|
|
{
|
|
core_names.push( core_name );
|
|
}
|
|
core_names.sort();
|
|
|
|
var core_count = core_names.length;
|
|
var cores = {};
|
|
|
|
for( var i = 0; i < core_count; i++ )
|
|
{
|
|
var core_name = core_names[i];
|
|
cores[core_name] = cores_status[core_name];
|
|
}
|
|
|
|
return cores;
|
|
};
|
|
|
|
this.set_cores_data = function set_cores_data( cores )
|
|
{
|
|
that.cores_data = sort_cores_data( cores.status );
|
|
|
|
that.menu_element
|
|
.empty();
|
|
|
|
var core_list = [];
|
|
core_list.push( '<option></option>' );
|
|
|
|
var core_count = 0;
|
|
for( var core_name in that.cores_data )
|
|
{
|
|
core_count++;
|
|
var core_path = config.solr_path + '/' + core_name;
|
|
var classes = [];
|
|
|
|
if( cores.status[core_name]['isDefaultCore'] )
|
|
{
|
|
classes.push( 'default' );
|
|
}
|
|
|
|
var core_tpl = '<option '
|
|
+ ' id="' + core_name.replace( /\./g, '__' ) + '" '
|
|
+ ' class="' + classes.join( ' ' ) + '"'
|
|
+ ' data-basepath="' + core_path + '"'
|
|
+ ' schema="' + cores.status[core_name]['schema'] + '"'
|
|
+ ' config="' + cores.status[core_name]['config'] + '"'
|
|
+ ' value="#/' + core_name + '"'
|
|
+ ' title="' + core_name + '"'
|
|
+ '>'
|
|
+ core_name
|
|
+ '</option>';
|
|
|
|
core_list.push( core_tpl );
|
|
}
|
|
|
|
var has_cores = 0 !== core_count;
|
|
if( has_cores )
|
|
{
|
|
that.menu_element
|
|
.append( core_list.join( "\n" ) )
|
|
.trigger( 'liszt:updated' );
|
|
}
|
|
|
|
var core_selector = $( '#core-selector' );
|
|
|
|
if( has_cores )
|
|
{
|
|
var cores_element = core_selector.find( '#has-cores' );
|
|
var selector_width = cores_element.width();
|
|
|
|
cores_element.find( '.chzn-container' )
|
|
.css( 'width', selector_width + 'px' );
|
|
|
|
cores_element.find( '.chzn-drop' )
|
|
.css( 'width', ( selector_width - 2 ) + 'px' );
|
|
}
|
|
};
|
|
|
|
this.run = function()
|
|
{
|
|
$.ajax
|
|
(
|
|
{
|
|
// load cores (indexInfo = false
|
|
success : function( response )
|
|
{
|
|
check_fixed_menu();
|
|
$( window ).resize( check_fixed_menu );
|
|
|
|
var system_url = config.solr_path + '/admin/info/system?wt=json';
|
|
$.ajax
|
|
(
|
|
{
|
|
url : system_url,
|
|
dataType : 'json',
|
|
beforeSend : function( arr, form, options )
|
|
{
|
|
},
|
|
success : function( response )
|
|
{
|
|
that.dashboard_values = response;
|
|
|
|
var environment_args = null;
|
|
var cloud_args = null;
|
|
|
|
if( response.jvm && response.jvm.jmx && response.jvm.jmx.commandLineArgs )
|
|
{
|
|
var command_line_args = response.jvm.jmx.commandLineArgs.join( ' | ' );
|
|
|
|
environment_args = command_line_args.match( /-Dsolr.environment=((dev|test|prod)?[\w\d]*)/i );
|
|
}
|
|
|
|
// @todo detect $scope.isCloud = response.mode.match( /solrcloud/i );
|
|
|
|
// environment
|
|
|
|
var wrapper = $( '#wrapper' );
|
|
var environment_element = $( '#environment' );
|
|
if( environment_args )
|
|
{
|
|
wrapper
|
|
.addClass( 'has-environment' );
|
|
|
|
if( environment_args[1] )
|
|
{
|
|
environment_element
|
|
.html( environment_args[1] );
|
|
}
|
|
|
|
if( environment_args[2] )
|
|
{
|
|
environment_element
|
|
.addClass( environment_args[2] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wrapper
|
|
.removeClass( 'has-environment' );
|
|
}
|
|
|
|
// cloud
|
|
|
|
var cloud_nav_element = $( '#menu #cloud' );
|
|
if( cloud_args )
|
|
{
|
|
cloud_nav_element
|
|
.show();
|
|
}
|
|
|
|
// sammy
|
|
|
|
sammy.run( location.hash );
|
|
},
|
|
error : function()
|
|
{
|
|
show_global_error
|
|
(
|
|
'<div class="message"><p>Unable to load environment info from <code>' + system_url.esc() + '</code>.</p>' +
|
|
'<p>This interface requires that you activate the admin request handlers in all SolrCores by adding the ' +
|
|
'following configuration to your <code>solrconfig.xml</code>:</p></div>' + "\n" +
|
|
|
|
'<div class="code"><pre class="syntax language-xml"><code>' +
|
|
'<!-- Admin Handlers - This will register all the standard admin RequestHandlers. -->'.esc() + "\n" +
|
|
'<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />'.esc() +
|
|
'</code></pre></div>'
|
|
);
|
|
};
|
|
|
|
check_fixed_menu = function check_fixed_menu()
|
|
{
|
|
$( '#wrapper' ).toggleClass( 'scroll', $( window ).height() < $( '#menu-wrapper' ).height() + $( '#header' ).height() + 40 );
|
|
}
|
|
*/
|