| /* |
| 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/:corename', { |
| templateUrl: 'partials/cores.html', |
| controller: 'CoreAdminController' |
| }). |
| when('/~collections', { |
| templateUrl: 'partials/collections.html', |
| controller: 'CollectionsController' |
| }). |
| when('/~collections/:collection', { |
| templateUrl: 'partials/collections.html', |
| controller: 'CollectionsController' |
| }). |
| 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/collection-overview', { |
| templateUrl: 'partials/collection_overview.html', |
| controller: 'CollectionOverviewController' |
| }). |
| 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/stream', { |
| templateUrl: 'partials/stream.html', |
| controller: 'StreamController' |
| }). |
| 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', { |
| templateUrl: 'partials/schema.html', |
| controller: 'SchemaController' |
| }). |
| when('/:core/segments', { |
| templateUrl: 'partials/segments.html', |
| controller: 'SegmentsController' |
| }). |
| otherwise({ |
| redirectTo: '/' |
| }); |
| }]) |
| .constant('Constants', { |
| IS_ROOT_PAGE: 1, |
| IS_CORE_PAGE: 2, |
| IS_COLLECTION_PAGE: 3, |
| ROOT_URL: "/" |
| }) |
| .filter('uriencode', function() { |
| return window.encodeURIComponent; |
| }) |
| .filter('highlight', function($sce) { |
| return function(input, lang) { |
| if (lang && input && lang!="txt") 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); |
| } |
| }; |
| }) |
| .directive('escapePressed', function () { |
| return function (scope, element, attrs) { |
| element.bind("keydown keypress", function (event) { |
| if(event.which === 27) { |
| scope.$apply(function (){ |
| scope.$eval(attrs.escapePressed); |
| }); |
| event.preventDefault(); |
| } |
| }); |
| }; |
| }) |
| .directive('focusWhen', function($timeout) { |
| return { |
| link: function(scope, element, attrs) { |
| scope.$watch(attrs.focusWhen, function(value) { |
| if(value === true) { |
| $timeout(function() { |
| element[0].focus(); |
| }, 100); |
| } |
| }); |
| } |
| }; |
| }) |
| .directive('scrollableWhenSmall', function($window) { |
| return { |
| link: function(scope, element, attrs) { |
| var w = angular.element($window); |
| |
| var checkFixedMenu = function() { |
| var shouldScroll = w.height() < (element.height() + $('#header').height() + 40); |
| element.toggleClass( 'scroll', shouldScroll); |
| }; |
| w.bind('resize', checkFixedMenu); |
| w.bind('load', checkFixedMenu); |
| } |
| } |
| }) |
| .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]; |
| } |
| |
| return ( input || 0 ).toString().replace(/\B(?=(\d{3})+(?!\d))/g, |
| sep[ browser.locale ] || sep[ browser.language ] || sep['_']); |
| }; |
| }) |
| .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'); |
| } |
| if ($rootScope.exceptions[config.url]) { |
| delete $rootScope.exceptions[config.url]; |
| } |
| 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.headers.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.exceptions[rejection.config.url] = rejection.data.error; |
| } |
| 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, Collections, System, Ping, Constants) { |
| |
| $rootScope.exceptions={}; |
| |
| $rootScope.toggleException = function() { |
| $scope.showException=!$scope.showException; |
| }; |
| |
| $scope.refresh = function() { |
| $scope.cores = []; |
| $scope.collections = []; |
| } |
| |
| $scope.refresh(); |
| $scope.resetMenu = function(page, pageType) { |
| Cores.list(function(data) { |
| $scope.cores = []; |
| var currentCoreName = $route.current.params.core; |
| delete $scope.currentCore; |
| for (key in data.status) { |
| var core = data.status[key]; |
| $scope.cores.push(core); |
| if ((!$scope.isSolrCloud || pageType == Constants.IS_CORE_PAGE) && core.name == currentCoreName) { |
| $scope.currentCore = core; |
| } |
| } |
| $scope.showInitFailures = Object.keys(data.initFailures).length>0; |
| $scope.initFailures = data.initFailures; |
| }); |
| |
| System.get(function(data) { |
| $scope.isCloudEnabled = data.mode.match( /solrcloud/i ); |
| |
| if ($scope.isCloudEnabled) { |
| Collections.list(function (data) { |
| $scope.collections = []; |
| var currentCollectionName = $route.current.params.core; |
| delete $scope.currentCollection; |
| for (key in data.collections) { |
| var collection = {name: data.collections[key]}; |
| $scope.collections.push(collection); |
| if (pageType == Constants.IS_COLLECTION_PAGE && collection.name == currentCollectionName) { |
| $scope.currentCollection = collection; |
| } |
| } |
| }) |
| } |
| |
| }); |
| |
| $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.showPing = true; |
| $scope.pingMS = data.responseHeader.QTime; |
| }); |
| // @todo .attr( 'title', '/admin/ping is not configured (' + xhr.status + ': ' + error_thrown + ')' ); |
| }; |
| |
| $scope.dumpCloud = function() { |
| $scope.$broadcast("cloud-dump"); |
| } |
| |
| $scope.showCore = function(core) { |
| $location.url("/" + core.name); |
| } |
| |
| $scope.showCollection = function(collection) { |
| $location.url("/" + collection.name + "/collection-overview") |
| } |
| |
| $scope.$on('$routeChangeStart', function() { |
| $rootScope.exceptions = {}; |
| }); |
| }); |
| |
| |
| (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 ) |
| { |
| |
| 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() |
| { |
| }; |
| */ |