first commit
Цей коміт міститься в:
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
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",
|
||||
"ab-base64"
|
||||
]);
|
||||
|
||||
solrAdminApp.config([
|
||||
'$routeProvider', function($routeProvider) {
|
||||
$routeProvider.
|
||||
when('/', {
|
||||
templateUrl: 'partials/index.html',
|
||||
controller: 'IndexController'
|
||||
}).
|
||||
when('/login', {
|
||||
templateUrl: 'partials/login.html',
|
||||
controller: 'LoginController'
|
||||
}).
|
||||
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('/~cluster-suggestions', {
|
||||
templateUrl: 'partials/cluster_suggestions.html',
|
||||
controller: 'ClusterSuggestionsController'
|
||||
}).
|
||||
when('/:core/core-overview', {
|
||||
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" && lang!="csv") 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, $location, $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++;
|
||||
if (sessionStorage.getItem("auth.header")) {
|
||||
config.headers['Authorization'] = sessionStorage.getItem("auth.header");
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (!$location.path().startsWith('/login')) {
|
||||
sessionStorage.removeItem("http401");
|
||||
sessionStorage.removeItem("auth.state");
|
||||
sessionStorage.removeItem("auth.statusText");
|
||||
}
|
||||
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 if (rejection.status === 401) {
|
||||
// Authentication redirect
|
||||
var headers = rejection.headers();
|
||||
var wwwAuthHeader = headers['www-authenticate'];
|
||||
sessionStorage.setItem("auth.wwwAuthHeader", wwwAuthHeader);
|
||||
sessionStorage.setItem("auth.statusText", rejection.statusText);
|
||||
sessionStorage.setItem("http401", "true");
|
||||
sessionStorage.removeItem("auth.scheme");
|
||||
sessionStorage.removeItem("auth.realm");
|
||||
sessionStorage.removeItem("auth.username");
|
||||
sessionStorage.removeItem("auth.header");
|
||||
sessionStorage.removeItem("auth.state");
|
||||
if ($location.path().includes('/login')) {
|
||||
if (!sessionStorage.getItem("auth.location")) {
|
||||
sessionStorage.setItem("auth.location", "/");
|
||||
}
|
||||
} else {
|
||||
sessionStorage.setItem("auth.location", $location.path());
|
||||
$location.path('/login');
|
||||
}
|
||||
} 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");
|
||||
// Force BasicAuth plugin to serve us a 'Authorization: xBasic xxxx' header so browser will not pop up login dialogue
|
||||
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
})
|
||||
.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.currentUser = sessionStorage.getItem("auth.username");
|
||||
$scope.http401 = sessionStorage.getItem("http401");
|
||||
};
|
||||
|
||||
$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 + "/core-overview");
|
||||
}
|
||||
|
||||
$scope.showCollection = function(collection) {
|
||||
$location.url("/" + collection.name + "/collection-overview")
|
||||
}
|
||||
|
||||
$scope.$on('$routeChangeStart', function() {
|
||||
$rootScope.exceptions = {};
|
||||
});
|
||||
});
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('AnalysisController',
|
||||
function($scope, $location, $routeParams, Luke, Analysis, Constants) {
|
||||
$scope.resetMenu("analysis", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
Luke.schema({core: $routeParams.core}, function(data) {
|
||||
$scope.fieldsAndTypes = [];
|
||||
for (var field in data.schema.fields) {
|
||||
$scope.fieldsAndTypes.push({
|
||||
group: "Fields",
|
||||
value: "fieldname=" + field,
|
||||
label: field});
|
||||
}
|
||||
for (var type in data.schema.types) {
|
||||
$scope.fieldsAndTypes.push({
|
||||
group: "Types",
|
||||
value: "fieldtype=" + type,
|
||||
label: type});
|
||||
}
|
||||
$scope.core = $routeParams.core;
|
||||
});
|
||||
|
||||
$scope.parseQueryString();
|
||||
// @todo - set defaultSearchField either to context["analysis.fieldname"] or context["analysis.fieldtype"]
|
||||
|
||||
};
|
||||
$scope.verbose = true;
|
||||
|
||||
var getShortComponentName = function(longname) {
|
||||
var short = -1 !== longname.indexOf( '$' )
|
||||
? longname.split( '$' )[1]
|
||||
: longname.split( '.' ).pop();
|
||||
return short.match( /[A-Z]/g ).join( '' );
|
||||
};
|
||||
|
||||
var getCaptionsForComponent = function(data) {
|
||||
var captions = [];
|
||||
for (var key in data[0]) {
|
||||
key = key.replace(/.*#/,'');
|
||||
if (key != "match" && key!="positionHistory") {
|
||||
captions.push(key.replace(/.*#/,''));
|
||||
}
|
||||
}
|
||||
return captions;
|
||||
};
|
||||
|
||||
var getTokensForComponent = function(data) {
|
||||
var tokens = [];
|
||||
var previousPosition = 0;
|
||||
var index=0;
|
||||
for (var i in data) {
|
||||
var tokenhash = data[i];
|
||||
var positionDifference = tokenhash.position - previousPosition;
|
||||
for (var j=positionDifference; j>1; j--) {
|
||||
tokens.push({position: tokenhash.position - j+1, blank:true, index:index++});
|
||||
}
|
||||
|
||||
var token = {position: tokenhash.position, keys:[], index:index++};
|
||||
|
||||
for (key in tokenhash) {
|
||||
if (key == "match" || key=="positionHistory") {
|
||||
//skip, to not display these keys in the UI
|
||||
} else {
|
||||
var tokenInfo = new Object();
|
||||
tokenInfo.name = key;
|
||||
tokenInfo.value = tokenhash[key];
|
||||
if ('text' === key || 'raw_bytes' === key ) {
|
||||
if (tokenhash.match) {
|
||||
tokenInfo.extraclass = 'match'; //to highlight matching text strings
|
||||
}
|
||||
}
|
||||
token.keys.push(tokenInfo);
|
||||
}
|
||||
}
|
||||
tokens.push(token);
|
||||
previousPosition = tokenhash.position;
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
var extractComponents = function(data, result, name) {
|
||||
if (data) {
|
||||
result[name] = [];
|
||||
for (var i = 0; i < data.length; i += 2) {
|
||||
var component = {
|
||||
name: data[i],
|
||||
short: getShortComponentName(data[i]),
|
||||
captions: getCaptionsForComponent(data[i + 1]),
|
||||
tokens: getTokensForComponent(data[i + 1])
|
||||
};
|
||||
result[name].push(component);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var processAnalysisData = function(analysis, fieldOrType) {
|
||||
var fieldname;
|
||||
for (fieldname in analysis[fieldOrType]) {console.log(fieldname);break;}
|
||||
var response = {};
|
||||
extractComponents(analysis[fieldOrType][fieldname].index, response, "index");
|
||||
extractComponents(analysis[fieldOrType][fieldname].query, response, "query");
|
||||
return response;
|
||||
};
|
||||
|
||||
$scope.updateQueryString = function() {
|
||||
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
var fieldOrType = parts[0];
|
||||
var name = parts[1];
|
||||
|
||||
if ($scope.indexText) {
|
||||
$location.search("analysis.fieldvalue", $scope.indexText);
|
||||
} else if ($location.search()["analysis.fieldvalue"]) {
|
||||
$location.search("analysis.fieldvalue", null);
|
||||
}
|
||||
if ($scope.queryText) {
|
||||
$location.search("analysis.query", $scope.queryText);
|
||||
} else if ($location.search()["analysis.query"]) {
|
||||
$location.search("analysis.query", null);
|
||||
}
|
||||
|
||||
if (fieldOrType == "fieldname") {
|
||||
$location.search("analysis.fieldname", name);
|
||||
$location.search("analysis.fieldtype", null);
|
||||
} else {
|
||||
$location.search("analysis.fieldtype", name);
|
||||
$location.search("analysis.fieldname", null);
|
||||
}
|
||||
$location.search("verbose_output", $scope.verbose ? "1" : "0");
|
||||
};
|
||||
|
||||
$scope.parseQueryString = function () {
|
||||
var params = {};
|
||||
var search = $location.search();
|
||||
|
||||
if (Object.keys(search).length == 0) {
|
||||
return;
|
||||
}
|
||||
for (var key in search) {
|
||||
params[key]=search[key];
|
||||
}
|
||||
$scope.indexText = search["analysis.fieldvalue"];
|
||||
$scope.queryText = search["analysis.query"];
|
||||
if (search["analysis.fieldname"]) {
|
||||
$scope.fieldOrType = "fieldname=" + search["analysis.fieldname"];
|
||||
$scope.schemaBrowserUrl = "field=" + search["analysis.fieldname"];
|
||||
} else {
|
||||
$scope.fieldOrType = "fieldtype=" + search["analysis.fieldtype"];
|
||||
$scope.schemaBrowserUrl = "type=" + search["analysis.fieldtype"];
|
||||
}
|
||||
if (search["verbose_output"] == undefined) {
|
||||
$scope.verbose = true;
|
||||
} else {
|
||||
$scope.verbose = search["verbose_output"] == "1";
|
||||
}
|
||||
|
||||
if ($scope.fieldOrType || $scope.indexText || $scope.queryText) {
|
||||
params.core = $routeParams.core;
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
var fieldOrType = parts[0] == "fieldname" ? "field_names" : "field_types";
|
||||
|
||||
Analysis.field(params, function(data) {
|
||||
$scope.result = processAnalysisData(data.analysis, fieldOrType);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.changeFieldOrType = function() {
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
if (parts[0]=='fieldname') {
|
||||
$scope.schemaBrowserUrl = "field=" + parts[1];
|
||||
} else {
|
||||
$scope.schemaBrowserUrl = "type=" + parts[1];
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleVerbose = function() {
|
||||
$scope.verbose = !$scope.verbose;
|
||||
$scope.updateQueryString();
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
+1024
Різницю між файлами не показано, бо вона завелика
Завантажити різницю
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
solrAdminApp.controller('ClusterSuggestionsController',
|
||||
function($scope, $http, Constants) {
|
||||
$scope.resetMenu("cluster-suggestion", Constants.IS_COLLECTION_PAGE);
|
||||
$scope.data={};
|
||||
var dataArr =[];
|
||||
var dataJson = {};
|
||||
//function to display suggestion
|
||||
$http({
|
||||
method: 'GET',
|
||||
url: '/api/cluster/autoscaling/suggestions'
|
||||
}).then(function successCallback(response) {
|
||||
$scope.data = response.data;
|
||||
$scope.parsedData = $scope.data.suggestions;
|
||||
}, function errorCallback(response) {
|
||||
});
|
||||
//function to perform operation
|
||||
$scope.postdata = function (x) {
|
||||
x.loading = true;
|
||||
var path=x.operation.path;
|
||||
var command=x.operation.command;
|
||||
var fullPath='/api/'+path;
|
||||
console.log(fullPath);
|
||||
console.log(command);
|
||||
$http.post(fullPath, JSON.stringify(command)).then(function (response) {
|
||||
if (response.data)
|
||||
console.log(response.data);
|
||||
x.loading = false;
|
||||
x.done = true;
|
||||
x.run=true;
|
||||
$scope.msg = "Command Submitted Successfully!";
|
||||
}, function (response) {
|
||||
x.failed=true;
|
||||
$scope.msg = "Service does not exist";
|
||||
$scope.statusval = response.status;
|
||||
$scope.statustext = response.statusText;
|
||||
$scope.headers = response.headers();
|
||||
});
|
||||
};
|
||||
$scope.showPopover = function() {
|
||||
$scope.popup = true;
|
||||
};
|
||||
|
||||
$scope.hidePopover = function () {
|
||||
$scope.popup = false;
|
||||
};
|
||||
});
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CollectionOverviewController',
|
||||
function($scope, $routeParams, Collections, Constants) {
|
||||
$scope.resetMenu("collection-overview", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
Collections.status({}, function(data) {
|
||||
$scope.selectedCollection = data.cluster.collections[$routeParams.core];
|
||||
$scope.selectedCollection.name = $routeParams.core;
|
||||
$scope.rootUrl = Constants.ROOT_URL;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showReplica = function(replica) {
|
||||
replica.show = !replica.show;
|
||||
}
|
||||
|
||||
$scope.hideShard = function(shard) {
|
||||
shard.hide = !shard.hide;
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CollectionsController',
|
||||
function($scope, $routeParams, $location, $timeout, Collections, Zookeeper, Constants){
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
|
||||
$scope.rootUrl = Constants.ROOT_URL + "#/~collections/" + $routeParams.collection;
|
||||
|
||||
Collections.status(function (data) {
|
||||
$scope.collections = [];
|
||||
for (var name in data.cluster.collections) {
|
||||
var collection = data.cluster.collections[name];
|
||||
collection.name = name;
|
||||
var shards = collection.shards;
|
||||
collection.shards = [];
|
||||
for (var shardName in shards) {
|
||||
var shard = shards[shardName];
|
||||
shard.name = shardName;
|
||||
shard.collection = collection.name;
|
||||
var replicas = shard.replicas;
|
||||
shard.replicas = [];
|
||||
for (var replicaName in replicas) {
|
||||
var replica = replicas[replicaName];
|
||||
replica.name = replicaName;
|
||||
replica.collection = collection.name;
|
||||
replica.shard = shard.name;
|
||||
shard.replicas.push(replica);
|
||||
}
|
||||
collection.shards.push(shard);
|
||||
}
|
||||
$scope.collections.push(collection);
|
||||
if ($routeParams.collection == name) {
|
||||
$scope.collection = collection;
|
||||
}
|
||||
}
|
||||
if ($routeParams.collection && !$scope.collection) {
|
||||
alert("No collection called " + $routeParams.collection)
|
||||
$location.path("/~collections");
|
||||
}
|
||||
$scope.liveNodes = data.cluster.liveNodes;
|
||||
});
|
||||
Zookeeper.configs(function(data) {
|
||||
$scope.configs = [];
|
||||
var items = data.tree[0].children;
|
||||
for (var i in items) {
|
||||
$scope.configs.push({name: items[i].data.title});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showRename = false;
|
||||
$scope.showAdd = false;
|
||||
$scope.showDelete = false;
|
||||
$scope.showSwap = false;
|
||||
$scope.showCreateAlias = false;
|
||||
$scope.showDeleteAlias = false;
|
||||
};
|
||||
|
||||
$scope.showAddCollection = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showAdd = true;
|
||||
$scope.newCollection = {
|
||||
name: "",
|
||||
routerName: "compositeId",
|
||||
numShards: 1,
|
||||
configName: "",
|
||||
replicationFactor: 1,
|
||||
maxShardsPerNode: 1,
|
||||
autoAddReplicas: 'false'
|
||||
};
|
||||
};
|
||||
|
||||
$scope.toggleCreateAlias = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showCreateAlias = true;
|
||||
}
|
||||
|
||||
$scope.toggleDeleteAlias = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showDeleteAlias = true;
|
||||
Zookeeper.aliases({}, function(data){
|
||||
if (Object.keys(data.aliases).length == 0) {
|
||||
delete $scope.aliases;
|
||||
} else {
|
||||
$scope.aliases = data.aliases;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$scope.cancelCreateAlias = $scope.cancelDeleteAlias = function() {
|
||||
$scope.hideAll();
|
||||
}
|
||||
|
||||
$scope.createAlias = function() {
|
||||
var collections = [];
|
||||
for (var i in $scope.aliasCollections) {
|
||||
collections.push($scope.aliasCollections[i].name);
|
||||
}
|
||||
Collections.createAlias({name: $scope.aliasToCreate, collections: collections.join(",")}, function(data) {
|
||||
$scope.hideAll();
|
||||
});
|
||||
}
|
||||
$scope.deleteAlias = function() {
|
||||
Collections.deleteAlias({name: $scope.aliasToDelete}, function(data) {
|
||||
$scope.hideAll();
|
||||
});
|
||||
|
||||
};
|
||||
$scope.addCollection = function() {
|
||||
if (!$scope.newCollection.name) {
|
||||
$scope.addMessage = "Please provide a core name";
|
||||
} else if (false) { //@todo detect whether core exists
|
||||
$scope.AddMessage = "A core with that name already exists";
|
||||
} else {
|
||||
var coll = $scope.newCollection;
|
||||
var params = {
|
||||
name: coll.name,
|
||||
"router.name": coll.routerName,
|
||||
numShards: coll.numShards,
|
||||
"collection.configName": coll.configName,
|
||||
replicationFactor: coll.replicationFactor,
|
||||
maxShardsPerNode: coll.maxShardsPerNode,
|
||||
autoAddReplicas: coll.autoAddReplicas
|
||||
};
|
||||
if (coll.shards) params.shards = coll.shards;
|
||||
if (coll.routerField) params["router.field"] = coll.routerField;
|
||||
Collections.add(params, function(data) {
|
||||
$scope.cancelAddCollection();
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
$location.path("/~collections/" + $scope.newCollection.name);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelAddCollection = function() {
|
||||
delete $scope.addMessage;
|
||||
$scope.showAdd = false;
|
||||
};
|
||||
|
||||
$scope.showDeleteCollection = function() {
|
||||
$scope.hideAll();
|
||||
if ($scope.collection) {
|
||||
$scope.showDelete = true;
|
||||
} else {
|
||||
alert("No collection selected.");
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteCollection = function() {
|
||||
if ($scope.collection.name == $scope.collectionDeleteConfirm) {
|
||||
Collections.delete({name: $scope.collection.name}, function (data) {
|
||||
$location.path("/~collections");
|
||||
});
|
||||
} else {
|
||||
$scope.deleteMessage = "Collection names do not match.";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.reloadCollection = function() {
|
||||
if (!$scope.collection) {
|
||||
alert("No collection selected.");
|
||||
return;
|
||||
}
|
||||
Collections.reload({name: $scope.collection.name},
|
||||
function(successData) {
|
||||
$scope.reloadSuccess = true;
|
||||
$timeout(function() {$scope.reloadSuccess=false}, 1000);
|
||||
},
|
||||
function(failureData) {
|
||||
$scope.reloadFailure = true;
|
||||
$timeout(function() {$scope.reloadFailure=false}, 1000);
|
||||
$location.path("/~collections");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleAddReplica = function(shard) {
|
||||
$scope.hideAll();
|
||||
shard.showAdd = !shard.showAdd;
|
||||
delete $scope.addReplicaMessage;
|
||||
|
||||
Zookeeper.liveNodes({}, function(data) {
|
||||
$scope.nodes = [];
|
||||
var children = data.tree[0].children;
|
||||
for (var child in children) {
|
||||
$scope.nodes.push(children[child].data.title);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleRemoveReplica = function(replica) {
|
||||
$scope.hideAll();
|
||||
replica.showRemove = !replica.showRemove;
|
||||
};
|
||||
|
||||
$scope.toggleRemoveShard = function(shard) {
|
||||
$scope.hideAll();
|
||||
shard.showRemove = !shard.showRemove;
|
||||
};
|
||||
|
||||
$scope.deleteShard = function(shard) {
|
||||
Collections.deleteShard({collection: shard.collection, shard:shard.name}, function(data) {
|
||||
shard.deleted = true;
|
||||
$timeout(function() {
|
||||
$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteReplica = function(replica) {
|
||||
Collections.deleteReplica({collection: replica.collection, shard:replica.shard, replica:replica.name}, function(data) {
|
||||
replica.deleted = true;
|
||||
$timeout(function() {
|
||||
$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
$scope.addReplica = function(shard) {
|
||||
var params = {
|
||||
collection: shard.collection,
|
||||
shard: shard.name,
|
||||
}
|
||||
if (shard.replicaNodeName && shard.replicaNodeName != "") {
|
||||
params.node = shard.replicaNodeName;
|
||||
}
|
||||
Collections.addReplica(params, function(data) {
|
||||
shard.replicaAdded = true;
|
||||
$timeout(function () {
|
||||
shard.replicaAdded = false;
|
||||
shard.showAdd = false;
|
||||
$$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleShard = function(shard) {
|
||||
shard.show = !shard.show;
|
||||
}
|
||||
|
||||
$scope.toggleReplica = function(replica) {
|
||||
replica.show = !replica.show;
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
|
||||
var flatten = function(data) {
|
||||
var list = [];
|
||||
for (var name in data) {
|
||||
var entry = data[name];
|
||||
entry.name = name;
|
||||
list.push(entry);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CoreOverviewController',
|
||||
function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication, Ping, Constants) {
|
||||
$scope.resetMenu("overview", Constants.IS_CORE_PAGE);
|
||||
$scope.refreshIndex = function() {
|
||||
Luke.index({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.index = data.index;
|
||||
delete $scope.statsMessage;
|
||||
},
|
||||
function(error) {
|
||||
$scope.statsMessage = "Luke is not configured";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.refreshReplication = function() {
|
||||
Replication.details({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.isSlave = data.details.isSlave == "true";
|
||||
$scope.isMaster = data.details.isMaster == "true";
|
||||
$scope.replication = data.details;
|
||||
},
|
||||
function(error) {
|
||||
$scope.replicationMessage = "Replication is not configured";
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refreshSystem = function() {
|
||||
CoreSystem.get({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.core = data.core;
|
||||
delete $scope.systemMessage;
|
||||
},
|
||||
function(error) {
|
||||
$scope.systemMessage = "/admin/system Handler is not configured";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.refreshPing = function() {
|
||||
Ping.status({core: $routeParams.core}, function(data) {
|
||||
if (data.error) {
|
||||
$scope.healthcheckStatus = false;
|
||||
if (data.error.code == 503) {
|
||||
$scope.healthcheckMessage = 'Ping request handler is not configured with a healthcheck file.';
|
||||
}
|
||||
} else {
|
||||
$scope.healthcheckStatus = data.status == "enabled";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleHealthcheck = function() {
|
||||
if ($scope.healthcheckStatus) {
|
||||
Ping.disable(
|
||||
function(data) {$scope.healthcheckStatus = false},
|
||||
function(error) {$scope.healthcheckMessage = error}
|
||||
);
|
||||
} else {
|
||||
Ping.enable(
|
||||
function(data) {$scope.healthcheckStatus = true},
|
||||
function(error) {$scope.healthcheckMessage = error}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.refresh = function() {
|
||||
$scope.refreshIndex();
|
||||
$scope.refreshReplication();
|
||||
$scope.refreshSystem();
|
||||
$scope.refreshPing();
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CoreAdminController',
|
||||
function($scope, $routeParams, $location, $timeout, $route, Cores, Update, Constants){
|
||||
$scope.resetMenu("cores", Constants.IS_ROOT_PAGE);
|
||||
$scope.selectedCore = $routeParams.corename; // use 'corename' not 'core' to distinguish from /solr/:core/
|
||||
$scope.refresh = function() {
|
||||
Cores.get(function(data) {
|
||||
var coreCount = 0;
|
||||
var cores = data.status;
|
||||
for (_obj in cores) coreCount++;
|
||||
$scope.hasCores = coreCount >0;
|
||||
if (!$scope.selectedCore && coreCount==0) {
|
||||
$scope.showAddCore();
|
||||
return;
|
||||
} else if (!$scope.selectedCore) {
|
||||
for (firstCore in cores) break;
|
||||
$scope.selectedCore = firstCore;
|
||||
$location.path("/~cores/" + $scope.selectedCore).replace();
|
||||
}
|
||||
$scope.core = cores[$scope.selectedCore];
|
||||
$scope.corelist = [];
|
||||
$scope.swapCorelist = [];
|
||||
for (var core in cores) {
|
||||
$scope.corelist.push(cores[core]);
|
||||
if (cores[core] != $scope.core) {
|
||||
$scope.swapCorelist.push(cores[core]);
|
||||
}
|
||||
}
|
||||
if ($scope.swapCorelist.length>0) {
|
||||
$scope.swapOther = $scope.swapCorelist[0].name;
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.showAddCore = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showAdd = true;
|
||||
$scope.newCore = {
|
||||
name: "new_core",
|
||||
dataDir: "data",
|
||||
instanceDir: "new_core",
|
||||
config: "solrconfig.xml",
|
||||
schema: "schema.xml",
|
||||
collection: "",
|
||||
shard: ""
|
||||
};
|
||||
};
|
||||
|
||||
$scope.addCore = function() {
|
||||
if (!$scope.newCore.name) {
|
||||
$scope.addMessage = "Please provide a core name";
|
||||
} else if (false) { //@todo detect whether core exists
|
||||
$scope.AddMessage = "A core with that name already exists";
|
||||
} else {
|
||||
var params = {
|
||||
name: $scope.newCore.name,
|
||||
instanceDir: $scope.newCore.instanceDir,
|
||||
config: $scope.newCore.config,
|
||||
schema: $scope.newCore.schema,
|
||||
dataDir: $scope.newCore.dataDir
|
||||
};
|
||||
if ($scope.isCloud) {
|
||||
params.collection = $scope.newCore.collection;
|
||||
params.shard = $scope.newCore.shard;
|
||||
}
|
||||
Cores.add(params, function(data) {
|
||||
$location.path("/~cores/" + $scope.newCore.name);
|
||||
$scope.cancelAddCore();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelAddCore = function() {
|
||||
delete $scope.addMessage;
|
||||
$scope.showAdd = false
|
||||
};
|
||||
|
||||
$scope.unloadCore = function() {
|
||||
var answer = confirm( 'Do you really want to unload Core "' + $scope.selectedCore + '"?' );
|
||||
if( !answer ) return;
|
||||
Cores.unload({core: $scope.selectedCore}, function(data) {
|
||||
$location.path("/~cores");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showRenameCore = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showRename = true;
|
||||
};
|
||||
|
||||
$scope.renameCore = function() {
|
||||
if (!$scope.other) {
|
||||
$scope.renameMessage = "Please provide a new name for the " + $scope.selectedCore + " core";
|
||||
} else if ($scope.other == $scope.selectedCore) {
|
||||
$scope.renameMessage = "New name must be different from the current one";
|
||||
} else {
|
||||
Cores.rename({core:$scope.selectedCore, other: $scope.other}, function(data) {
|
||||
$location.path("/~cores/" + $scope.other);
|
||||
$scope.cancelRename();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelRenameCore = function() {
|
||||
$scope.showRename = false;
|
||||
delete $scope.renameMessage;
|
||||
$scope.other = "";
|
||||
};
|
||||
|
||||
$scope.showSwapCores = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showSwap = true;
|
||||
};
|
||||
|
||||
$scope.swapCores = function() {
|
||||
if (!$scope.swapOther) {
|
||||
$scope.swapMessage = "Please select a core to swap with";
|
||||
} else if ($scope.swapOther == $scope.selectedCore) {
|
||||
$scope.swapMessage = "Cannot swap with the same core";
|
||||
} else {
|
||||
Cores.swap({core: $scope.selectedCore, other: $scope.swapOther}, function(data) {
|
||||
$location.path("/~cores/" + $scope.swapOther);
|
||||
delete $scope.swapOther;
|
||||
$scope.cancelSwapCores();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelSwapCores = function() {
|
||||
delete $scope.swapMessage;
|
||||
$scope.showSwap = false;
|
||||
}
|
||||
|
||||
$scope.reloadCore = function() {
|
||||
if ($scope.initFailures[$scope.selectedCore]) {
|
||||
delete $scope.initFailures[$scope.selectedCore];
|
||||
$scope.showInitFailures = Object.keys(data.initFailures).length>0;
|
||||
}
|
||||
Cores.reload({core: $scope.selectedCore},
|
||||
function(data) {
|
||||
if (data.error) {
|
||||
$scope.reloadFailure = true;
|
||||
$timeout(function() {
|
||||
$scope.reloadFailure = false;
|
||||
$route.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
$scope.reloadSuccess = true;
|
||||
$timeout(function () {
|
||||
$scope.reloadSuccess = false;
|
||||
$route.reload();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showRename = false;
|
||||
$scope.showAdd = false;
|
||||
$scope.showSwap = false;
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
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 dataimport_timeout = 2000;
|
||||
|
||||
solrAdminApp.controller('DataImportController',
|
||||
function($scope, $rootScope, $routeParams, $location, $timeout, $interval, $cookies, Mbeans, DataImport, Constants) {
|
||||
$scope.resetMenu("dataimport", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Mbeans.info({core: $routeParams.core, cat: 'QUERY'}, function (data) {
|
||||
var mbeans = data['solr-mbeans'][1];
|
||||
$scope.handlers = [];
|
||||
for (var key in mbeans) {
|
||||
if (mbeans[key]['class'] !== key && mbeans[key]['class'] === 'org.apache.solr.handler.dataimport.DataImportHandler') {
|
||||
$scope.handlers.push(key);
|
||||
}
|
||||
}
|
||||
$scope.hasHandlers = $scope.handlers.length > 0;
|
||||
|
||||
if (!$routeParams.handler) {
|
||||
$location.path("/" + $routeParams.core + "/dataimport/" + $scope.handlers[0]);
|
||||
} else {
|
||||
$scope.currentHandler = $routeParams.handler;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.handler = $routeParams.handler;
|
||||
if ($scope.handler && $scope.handler[0]=="/") {
|
||||
$scope.handler = $scope.handler.substr(1);
|
||||
}
|
||||
if ($scope.handler) {
|
||||
DataImport.config({core: $routeParams.core, name: $scope.handler}, function (data) {
|
||||
try {
|
||||
$scope.config = data.config;
|
||||
var xml = $.parseXML(data.config);
|
||||
$scope.entities = [];
|
||||
$('document > entity', xml).each(function (i, element) {
|
||||
$scope.entities.push($(element).attr('name'));
|
||||
});
|
||||
$scope.refreshStatus();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.lastUpdate = "unknown";
|
||||
$scope.lastUpdateUTC = "";
|
||||
};
|
||||
|
||||
$scope.toggleDebug = function () {
|
||||
$scope.isDebugMode = !$scope.isDebugMode;
|
||||
if ($scope.isDebugMode) {
|
||||
// also enable Debug checkbox
|
||||
$scope.form.showDebug = true;
|
||||
}
|
||||
$scope.showConfiguration = true;
|
||||
}
|
||||
|
||||
$scope.toggleConfiguration = function () {
|
||||
$scope.showConfiguration = !$scope.showConfiguration;
|
||||
}
|
||||
|
||||
$scope.toggleRawStatus = function () {
|
||||
$scope.showRawStatus = !$scope.showRawStatus;
|
||||
}
|
||||
|
||||
$scope.toggleRawDebug = function () {
|
||||
$scope.showRawDebug = !$scope.showRawDebug;
|
||||
}
|
||||
|
||||
$scope.reload = function () {
|
||||
DataImport.reload({core: $routeParams.core, name: $scope.handler}, function () {
|
||||
$scope.reloaded = true;
|
||||
$timeout(function () {
|
||||
$scope.reloaded = false;
|
||||
}, 5000);
|
||||
$scope.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.form = {
|
||||
command: "full-import",
|
||||
verbose: false,
|
||||
clean: false,
|
||||
commit: true,
|
||||
showDebug: false,
|
||||
custom: "",
|
||||
core: $routeParams.core
|
||||
};
|
||||
|
||||
$scope.submit = function () {
|
||||
var params = {};
|
||||
for (var key in $scope.form) {
|
||||
if (key == "showDebug") {
|
||||
if ($scope.form.showDebug) {
|
||||
params["debug"] = true;
|
||||
}
|
||||
} else {
|
||||
params[key] = $scope.form[key];
|
||||
}
|
||||
}
|
||||
if (params.custom.length) {
|
||||
var customParams = $scope.form.custom.split("&");
|
||||
for (var i in customParams) {
|
||||
var parts = customParams[i].split("=");
|
||||
params[parts[0]] = parts[1];
|
||||
}
|
||||
}
|
||||
delete params.custom;
|
||||
|
||||
if ($scope.isDebugMode) {
|
||||
params.dataConfig = $scope.config;
|
||||
}
|
||||
|
||||
params.core = $routeParams.core;
|
||||
params.name = $scope.handler;
|
||||
|
||||
DataImport.post(params, function (data) {
|
||||
$scope.rawResponse = JSON.stringify(data, null, 2);
|
||||
$scope.refreshStatus();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.abort = function () {
|
||||
$scope.isAborting = true;
|
||||
DataImport.abort({core: $routeParams.core, name: $scope.handler}, function () {
|
||||
$timeout(function () {
|
||||
$scope.isAborting = false;
|
||||
$scope.refreshStatus();
|
||||
}, 4000);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.refreshStatus = function () {
|
||||
|
||||
console.log("Refresh Status");
|
||||
|
||||
$scope.isStatusLoading = true;
|
||||
DataImport.status({core: $routeParams.core, name: $scope.handler}, function (data) {
|
||||
if (data[0] == "<") {
|
||||
$scope.hasHandlers = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var now = new Date();
|
||||
$scope.lastUpdate = now.toTimeString().split(' ').shift();
|
||||
$scope.lastUpdateUTC = now.toUTCString();
|
||||
var messages = data.statusMessages;
|
||||
var messagesCount = 0;
|
||||
for( var key in messages ) { messagesCount++; }
|
||||
|
||||
if (data.status == 'busy') {
|
||||
$scope.status = "indexing";
|
||||
|
||||
$scope.timeElapsed = data.statusMessages['Time Elapsed'];
|
||||
$scope.elapsedSeconds = parseSeconds($scope.timeElapsed);
|
||||
|
||||
var info = $scope.timeElapsed ? 'Indexing since ' + $scope.timeElapsed : 'Indexing ...';
|
||||
$scope.info = showInfo(messages, true, info, $scope.elapsedSeconds);
|
||||
|
||||
} else if (messages.RolledBack) {
|
||||
$scope.status = "failure";
|
||||
$scope.info = showInfo(messages, true);
|
||||
} else if (messages.Aborted) {
|
||||
$scope.status = "aborted";
|
||||
$scope.info = showInfo(messages, true, 'Aborting current Import ...');
|
||||
} else if (data.status == "idle" && messagesCount != 0) {
|
||||
$scope.status = "success";
|
||||
$scope.info = showInfo(messages, true);
|
||||
} else {
|
||||
$scope.status = "idle";
|
||||
$scope.info = showInfo(messages, false, 'No information available (idle)');
|
||||
}
|
||||
|
||||
delete data.$promise;
|
||||
delete data.$resolved;
|
||||
|
||||
$scope.rawStatus = JSON.stringify(data, null, 2);
|
||||
|
||||
$scope.isStatusLoading = false;
|
||||
$scope.statusUpdated = true;
|
||||
$timeout(function () {
|
||||
$scope.statusUpdated = false;
|
||||
}, dataimport_timeout / 2);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateAutoRefresh = function () {
|
||||
$scope.autorefresh = !$scope.autorefresh;
|
||||
$cookies.dataimport_autorefresh = $scope.autorefresh ? true : null;
|
||||
if ($scope.autorefresh) {
|
||||
$scope.refreshTimeout = $interval($scope.refreshStatus, dataimport_timeout);
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
$interval.cancel($scope.refreshTimeout);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
|
||||
} else if ($scope.refreshTimeout) {
|
||||
$interval.cancel($scope.refreshTimeout);
|
||||
}
|
||||
$scope.refreshStatus();
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
|
||||
});
|
||||
|
||||
var showInfo = function (messages, showFull, info_text, elapsed_seconds) {
|
||||
|
||||
var info = {};
|
||||
if (info_text) {
|
||||
info.text = info_text;
|
||||
} else {
|
||||
info.text = messages[''] || '';
|
||||
// format numbers included in status nicely
|
||||
/* @todo this pretty printing is hard to work out how to do in an Angularesque way:
|
||||
info.text = info.text.replace(/\d{4,}/g,
|
||||
function (match, position, string) {
|
||||
return app.format_number(parseInt(match, 10));
|
||||
}
|
||||
);
|
||||
*/
|
||||
|
||||
var time_taken_text = messages['Time taken'];
|
||||
info.timeTaken = parseSeconds(time_taken_text);
|
||||
}
|
||||
info.showDetails = false;
|
||||
|
||||
if (showFull) {
|
||||
if (!elapsed_seconds) {
|
||||
var time_taken_text = messages['Time taken'];
|
||||
elapsed_seconds = parseSeconds(time_taken_text);
|
||||
}
|
||||
|
||||
info.showDetails = true;
|
||||
|
||||
var document_config = {
|
||||
'Requests': 'Total Requests made to DataSource',
|
||||
'Fetched': 'Total Rows Fetched',
|
||||
'Skipped': 'Total Documents Skipped',
|
||||
'Processed': 'Total Documents Processed'
|
||||
};
|
||||
|
||||
info.docs = [];
|
||||
for (var key in document_config) {
|
||||
var value = parseInt(messages[document_config[key]], 10);
|
||||
var doc = {desc: document_config[key], name: key, value: value};
|
||||
if (elapsed_seconds && key != 'Skipped') {
|
||||
doc.speed = Math.round(value / elapsed_seconds);
|
||||
}
|
||||
info.docs.push(doc);
|
||||
}
|
||||
|
||||
var dates_config = {
|
||||
'Started': 'Full Dump Started',
|
||||
'Aborted': 'Aborted',
|
||||
'Rolledback': 'Rolledback'
|
||||
};
|
||||
|
||||
info.dates = [];
|
||||
for (var key in dates_config) {
|
||||
var value = messages[dates_config[key]];
|
||||
if (value) {
|
||||
value = value.replace(" ", "T")+".000Z";
|
||||
console.log(value);
|
||||
var date = {desc: dates_config[key], name: key, value: value};
|
||||
info.dates.push(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
var parseSeconds = function(time) {
|
||||
var seconds = 0;
|
||||
var arr = new String(time || '').split('.');
|
||||
var parts = arr[0].split(':').reverse();
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
seconds += ( parseInt(parts[i], 10) || 0 ) * Math.pow(60, i);
|
||||
}
|
||||
|
||||
if (arr[1] && 5 <= parseInt(arr[1][0], 10)) {
|
||||
seconds++; // treat more or equal than .5 as additional second
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//helper for formatting JSON and others
|
||||
|
||||
var DOC_PLACEHOLDER = '<doc>\n' +
|
||||
'<field name="id">change.me</field>' +
|
||||
'<field name="title">change.me</field>' +
|
||||
'</doc>';
|
||||
|
||||
var ADD_PLACEHOLDER = '<add>\n' + DOC_PLACEHOLDER + '</add>\n';
|
||||
|
||||
solrAdminApp.controller('DocumentsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Luke, Update, FileUpload, Constants) {
|
||||
$scope.resetMenu("documents", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Luke.schema({core: $routeParams.core}, function(data) {
|
||||
//TODO: handle dynamic fields
|
||||
delete data.schema.fields._version_;
|
||||
$scope.fields = Object.keys(data.schema.fields);
|
||||
});
|
||||
$scope.document = "";
|
||||
$scope.handler = "/update";
|
||||
$scope.type = "json";
|
||||
$scope.commitWithin = 1000;
|
||||
$scope.overwrite = true;
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
|
||||
$scope.changeDocumentType = function () {
|
||||
$scope.placeholder = "";
|
||||
if ($scope.type == 'json') {
|
||||
$scope.placeholder = '{"id":"change.me","title":"change.me"}';
|
||||
} else if ($scope.type == 'csv') {
|
||||
$scope.placeholder = "id,title\nchange.me,change.me";
|
||||
} else if ($scope.type == 'solr') {
|
||||
$scope.placeholder = ADD_PLACEHOLDER;
|
||||
} else if ($scope.type == 'xml') {
|
||||
$scope.placeholder = DOC_PLACEHOLDER;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addWizardField = function () {
|
||||
if ($scope.document == "") $scope.document = "{}";
|
||||
var doc = JSON.parse($scope.document);
|
||||
doc[$scope.fieldName] = $scope.fieldData;
|
||||
$scope.document = JSON.stringify(doc, null, '\t');
|
||||
$scope.fieldData = "";
|
||||
};
|
||||
|
||||
$scope.submit = function () {
|
||||
var contentType = "";
|
||||
var postData = "";
|
||||
var params = {};
|
||||
var doingFileUpload = false;
|
||||
|
||||
if ($scope.handler[0] == '/') {
|
||||
params.handler = $scope.handler.substring(1);
|
||||
} else {
|
||||
params.handler = 'update';
|
||||
params.qt = $scope.handler;
|
||||
}
|
||||
|
||||
params.commitWithin = $scope.commitWithin;
|
||||
params.overwrite = $scope.overwrite;
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
|
||||
if ($scope.type == "json" || $scope.type == "wizard") {
|
||||
postData = "[" + $scope.document + "]";
|
||||
contentType = "json";
|
||||
} else if ($scope.type == "csv") {
|
||||
postData = $scope.document;
|
||||
contentType = "csv";
|
||||
} else if ($scope.type == "xml") {
|
||||
postData = "<add>" + $scope.document + "</add>";
|
||||
contentType = "xml";
|
||||
} else if ($scope.type == "upload") {
|
||||
doingFileUpload = true;
|
||||
params.raw = $scope.literalParams;
|
||||
} else if ($scope.type == "solr") {
|
||||
postData = $scope.document;
|
||||
if (postData[0] == "<") {
|
||||
contentType = "xml";
|
||||
} else if (postData[0] == "{" || postData[0] == '[') {
|
||||
contentType = "json";
|
||||
} else {
|
||||
alert("Cannot identify content type")
|
||||
}
|
||||
}
|
||||
if (!doingFileUpload) {
|
||||
var callback = function (success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
};
|
||||
var failure = function (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
};
|
||||
if (contentType == "json") {
|
||||
Update.postJson(params, postData, callback, failure);
|
||||
} else if (contentType == "xml") {
|
||||
Update.postXml(params, postData, callback, failure);
|
||||
} else if (contentType == "csv") {
|
||||
Update.postCsv(params, postData, callback, failure);
|
||||
}
|
||||
} else {
|
||||
var file = $scope.fileUpload;
|
||||
console.log('file is ' + JSON.stringify(file));
|
||||
var uploadUrl = "/fileUpload";
|
||||
FileUpload.upload(params, $scope.fileUpload, function (success) {
|
||||
$scope.responseStatus = "success";
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
}, function (failure) {
|
||||
$scope.responseStatus = "failure";
|
||||
$scope.response = JSON.stringify(failure, null, ' ');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
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 contentTypeMap = { xml : 'text/xml', html : 'text/html', js : 'text/javascript', json : 'application/json', 'css' : 'text/css' };
|
||||
var languages = {js: "javascript", xml:"xml", xsl:"xml", vm: "xml", html: "xml", json: "json", css: "css"};
|
||||
|
||||
solrAdminApp.controller('FilesController',
|
||||
function($scope, $rootScope, $routeParams, $location, Files, Constants) {
|
||||
$scope.resetMenu("files", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.file = $location.search().file;
|
||||
$scope.content = null;
|
||||
|
||||
$scope.baseurl = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // Including /solr/ context
|
||||
|
||||
$scope.refresh = function () {
|
||||
|
||||
var process = function (path, tree) {
|
||||
var params = {core: $routeParams.core};
|
||||
if (path.slice(-1) == '/') {
|
||||
params.file = path.slice(0, -1);
|
||||
} else if (path!='') {
|
||||
params.file = path;
|
||||
}
|
||||
|
||||
Files.list(params, function (data) {
|
||||
var filenames = Object.keys(data.files);
|
||||
filenames.sort();
|
||||
for (var i in filenames) {
|
||||
var file = filenames[i];
|
||||
var filedata = data.files[file];
|
||||
var state = undefined;
|
||||
var children = undefined;
|
||||
|
||||
if (filedata.directory) {
|
||||
file = file + "/";
|
||||
if ($scope.file && $scope.file.indexOf(path + file) == 0) {
|
||||
state = "open";
|
||||
} else {
|
||||
state = "closed";
|
||||
}
|
||||
children = [];
|
||||
process(path + file, children);
|
||||
}
|
||||
tree.push({
|
||||
data: {
|
||||
title: file,
|
||||
attr: { id: path + file}
|
||||
},
|
||||
children: children,
|
||||
state: state
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.tree = [];
|
||||
process("", $scope.tree);
|
||||
|
||||
if ($scope.file && $scope.file != '' && $scope.file.split('').pop()!='/') {
|
||||
var extension;
|
||||
if ($scope.file == "managed-schema") {
|
||||
extension = contentTypeMap['xml'];
|
||||
} else {
|
||||
extension = $scope.file.match( /\.(\w+)$/)[1] || '';
|
||||
}
|
||||
var contentType = (contentTypeMap[extension] || 'text/plain' ) + ';charset=utf-8';
|
||||
|
||||
Files.get({core: $routeParams.core, file: $scope.file, contentType: contentType}, function(data) {
|
||||
$scope.content = data.data;
|
||||
$scope.url = data.config.url + "?" + $.param(data.config.params); // relative URL
|
||||
if (contentType.indexOf("text/plain") && (data.data.indexOf("<?xml")>=0) || data.data.indexOf("<!--")>=0) {
|
||||
$scope.lang = "xml";
|
||||
} else {
|
||||
$scope.lang = languages[extension] || "txt";
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showTreeLink = function(data) {
|
||||
var file = data.args[0].id;
|
||||
$location.search({file:file});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('IndexController', function($scope, System, Cores, Constants) {
|
||||
$scope.resetMenu("index", Constants.IS_ROOT_PAGE);
|
||||
$scope.reload = function() {
|
||||
System.get(function(data) {
|
||||
$scope.system = data;
|
||||
|
||||
// load average
|
||||
var load_average = ( data.system.uptime || '' ).match( /load averages?: (\d+[.,]\d\d),? (\d+[.,]\d\d),? (\d+[.,]\d\d)/ );
|
||||
if (load_average) {
|
||||
for (var i=0;i<2;i++) {
|
||||
load_average[i]=load_average[i].replace(",","."); // for European users
|
||||
}
|
||||
$scope.load_average = load_average.slice(1);
|
||||
}
|
||||
|
||||
// physical memory
|
||||
var memoryMax = parse_memory_value(data.system.totalPhysicalMemorySize);
|
||||
$scope.memoryTotal = parse_memory_value(data.system.totalPhysicalMemorySize - data.system.freePhysicalMemorySize);
|
||||
$scope.memoryPercentage = ($scope.memoryTotal / memoryMax * 100).toFixed(1)+ "%";
|
||||
$scope.memoryMax = pretty_print_bytes(memoryMax);
|
||||
$scope.memoryTotalDisplay = pretty_print_bytes($scope.memoryTotal);
|
||||
|
||||
// swap space
|
||||
var swapMax = parse_memory_value(data.system.totalSwapSpaceSize);
|
||||
$scope.swapTotal = parse_memory_value(data.system.totalSwapSpaceSize - data.system.freeSwapSpaceSize);
|
||||
$scope.swapPercentage = ($scope.swapTotal / swapMax * 100).toFixed(1)+ "%";
|
||||
$scope.swapMax = pretty_print_bytes(swapMax);
|
||||
$scope.swapTotalDisplay = pretty_print_bytes($scope.swapTotal);
|
||||
|
||||
// file handles
|
||||
$scope.fileDescriptorPercentage = (data.system.openFileDescriptorCount / data.system.maxFileDescriptorCount *100).toFixed(1) + "%";
|
||||
|
||||
// java memory
|
||||
var javaMemoryMax = parse_memory_value(data.jvm.memory.raw.max || data.jvm.memory.max);
|
||||
$scope.javaMemoryTotal = parse_memory_value(data.jvm.memory.raw.total || data.jvm.memory.total);
|
||||
$scope.javaMemoryUsed = parse_memory_value(data.jvm.memory.raw.used || data.jvm.memory.used);
|
||||
$scope.javaMemoryTotalPercentage = ($scope.javaMemoryTotal / javaMemoryMax *100).toFixed(1) + "%";
|
||||
$scope.javaMemoryUsedPercentage = ($scope.javaMemoryUsed / $scope.javaMemoryTotal *100).toFixed(1) + "%";
|
||||
$scope.javaMemoryPercentage = ($scope.javaMemoryUsed / javaMemoryMax * 100).toFixed(1) + "%";
|
||||
$scope.javaMemoryTotalDisplay = pretty_print_bytes($scope.javaMemoryTotal);
|
||||
$scope.javaMemoryUsedDisplay = pretty_print_bytes($scope.javaMemoryUsed); // @todo These should really be an AngularJS Filter: {{ javaMemoryUsed | bytes }}
|
||||
$scope.javaMemoryMax = pretty_print_bytes(javaMemoryMax);
|
||||
|
||||
// no info bar:
|
||||
$scope.noInfo = !(
|
||||
data.system.totalPhysicalMemorySize && data.system.freePhysicalMemorySize &&
|
||||
data.system.totalSwapSpaceSize && data.system.freeSwapSpaceSize &&
|
||||
data.system.openFileDescriptorCount && data.system.maxFileDescriptorCount);
|
||||
|
||||
// command line args:
|
||||
$scope.commandLineArgs = data.jvm.jmx.commandLineArgs.sort();
|
||||
});
|
||||
};
|
||||
$scope.reload();
|
||||
});
|
||||
|
||||
var parse_memory_value = function( value ) {
|
||||
if( value !== Number( value ) )
|
||||
{
|
||||
var units = 'BKMGTPEZY';
|
||||
var match = value.match( /^(\d+([,\.]\d+)?) (\w).*$/ );
|
||||
var value = parseFloat( match[1] ) * Math.pow( 1024, units.indexOf( match[3].toUpperCase() ) );
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
var pretty_print_bytes = function(byte_value) {
|
||||
var unit = null;
|
||||
|
||||
byte_value /= 1024;
|
||||
byte_value /= 1024;
|
||||
unit = 'MB';
|
||||
|
||||
if( 1024 <= byte_value ) {
|
||||
byte_value /= 1024;
|
||||
unit = 'GB';
|
||||
}
|
||||
return byte_value.toFixed( 2 ) + ' ' + unit;
|
||||
};
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('JavaPropertiesController',
|
||||
function($scope, Properties, Constants){
|
||||
$scope.resetMenu("java-props", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Properties.get(function(data) {
|
||||
var sysprops = data["system.properties"];
|
||||
var sep = sysprops["path.separator"]
|
||||
var props = [];
|
||||
for (var key in sysprops) {
|
||||
var value = sysprops[key];
|
||||
var key = key.replace(/\./g, '.​');
|
||||
if (key.indexOf(".path")!=-1 || key.indexOf(".dirs")) {
|
||||
var values = [];
|
||||
var parts = value.split(sep);
|
||||
for (var i in parts) {
|
||||
values.push({pos:i, value:parts[i]})
|
||||
}
|
||||
props.push({name: key, values: values});
|
||||
} else {
|
||||
props.push({name: key, values: [value]});
|
||||
}
|
||||
}
|
||||
$scope.props = props;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
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 format_time_content = function( time, timeZone ) {
|
||||
var format_time_options = {};
|
||||
if (timeZone && timeZone!="Local") {
|
||||
format_time_options.timeZone = timeZone;
|
||||
}
|
||||
return time.toLocaleString( undefined, format_time_options );
|
||||
}
|
||||
|
||||
solrAdminApp.controller('LoggingController',
|
||||
function($scope, $timeout, $cookies, Logging, Constants){
|
||||
$scope.resetMenu("logging", Constants.IS_ROOT_PAGE);
|
||||
$scope.timezone = $cookies.logging_timezone || "Local";
|
||||
$scope.refresh = function() {
|
||||
Logging.events(function(data) {
|
||||
$scope.since = new Date();
|
||||
$scope.sinceDisplay = format_time_content($scope.since, "Local");
|
||||
var events = data.history.docs;
|
||||
for (var i=0; i<events.length; i++) {
|
||||
var event = events[i];
|
||||
var time = new Date(event.time);
|
||||
event.local_time = format_time_content(time, "Local");
|
||||
event.utc_time = format_time_content(time, "UTC");
|
||||
event.loggerBase = event.logger.split( '.' ).pop();
|
||||
|
||||
if( !event.trace ) {
|
||||
var lines = event.message.split( "\n" );
|
||||
if( lines.length > 1) {
|
||||
event.trace = event.message;
|
||||
event.message = lines[0];
|
||||
}
|
||||
}
|
||||
event.message = event.message.replace(/,/g, ',​');
|
||||
event.showTrace = false;
|
||||
}
|
||||
$scope.events = events;
|
||||
$scope.watcher = data.watcher;
|
||||
/* @todo sticky_mode
|
||||
// state element is in viewport
|
||||
sticky_mode = ( state.position().top <= $( window ).scrollTop() + $( window ).height() - ( $( 'body' ).height() - state.position().top ) );
|
||||
// initial request
|
||||
if( 0 === since ) {
|
||||
sticky_mode = true;
|
||||
}
|
||||
$scope.loggingEvents = events;
|
||||
|
||||
if( sticky_mode )
|
||||
{
|
||||
$( 'body' )
|
||||
.animate
|
||||
(
|
||||
{ scrollTop: state.position().top },
|
||||
1000
|
||||
);
|
||||
}
|
||||
*/
|
||||
});
|
||||
$scope.timeout = $timeout($scope.refresh, 10000);
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
$timeout.cancel($scope.timeout);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
};
|
||||
$scope.refresh();
|
||||
$scope.toggleRefresh = function() {
|
||||
if(!$scope.stopped) {
|
||||
$scope.stopped = true;
|
||||
$timeout.cancel($scope.timeout);
|
||||
} else {
|
||||
$scope.stopped = false;
|
||||
$scope.timeout = $timeout($scope.refresh, 10000);
|
||||
}
|
||||
};
|
||||
$scope.toggleTimezone = function() {
|
||||
$scope.timezone = ($scope.timezone=="Local") ? "UTC":"Local";
|
||||
$cookies.logging_timezone = $scope.timezone;
|
||||
}
|
||||
$scope.toggleRow = function(event) {
|
||||
event.showTrace =! event.showTrace;
|
||||
};
|
||||
}
|
||||
)
|
||||
|
||||
.controller('LoggingLevelController',
|
||||
function($scope, Logging) {
|
||||
$scope.resetMenu("logging-levels");
|
||||
|
||||
var packageOf = function(logger) {
|
||||
var parts = logger.name.split(".");
|
||||
return !parts.pop() ? "" : parts.join(".");
|
||||
};
|
||||
|
||||
var shortNameOf = function(logger) {return logger.name.split(".").pop();}
|
||||
|
||||
var makeTree = function(loggers, packag) {
|
||||
var tree = [];
|
||||
for (var i=0; i<loggers.length; i++) {
|
||||
var logger = loggers[i];
|
||||
logger.packag = packageOf(logger);
|
||||
logger.short = shortNameOf(logger);
|
||||
if (logger.packag == packag) {
|
||||
logger.children = makeTree(loggers, logger.name);
|
||||
tree.push(logger);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
};
|
||||
|
||||
$scope.refresh = function() {
|
||||
Logging.levels(function(data) {
|
||||
$scope.logging = makeTree(data.loggers, "");
|
||||
$scope.watcher = data.watcher;
|
||||
$scope.levels = [];
|
||||
for (level in data.levels) {
|
||||
$scope.levels.push({name:data.levels[level], pos:level});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleOptions = function(logger) {
|
||||
if (logger.showOptions) {
|
||||
logger.showOptions = false;
|
||||
delete $scope.currentLogger;
|
||||
} else {
|
||||
if ($scope.currentLogger) {
|
||||
$scope.currentLogger.showOptions = false;
|
||||
}
|
||||
logger.showOptions = true;
|
||||
$scope.currentLogger = logger;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setLevel = function(logger, newLevel) {
|
||||
var setString = logger.name + ":" + newLevel;
|
||||
logger.showOptions = false;
|
||||
Logging.setLevel({set: setString}, function(data) {
|
||||
$scope.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('LoginController',
|
||||
['$scope', '$routeParams', '$rootScope', '$location', '$window', 'AuthenticationService', 'Constants',
|
||||
function ($scope, $routeParams, $rootScope, $location, $window, AuthenticationService, Constants) {
|
||||
$scope.resetMenu("login", Constants.IS_ROOT_PAGE);
|
||||
$scope.subPath = $routeParams.route;
|
||||
$rootScope.exceptions = {};
|
||||
|
||||
// Session variables set in app.js 401 interceptor
|
||||
var wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader");
|
||||
var authScheme = sessionStorage.getItem("auth.scheme");
|
||||
if (wwwAuthHeader) {
|
||||
// Parse www-authenticate header
|
||||
var wwwHeader = wwwAuthHeader.match(/(\w+)(\s+)?(.*)/);
|
||||
authScheme = "unknown";
|
||||
var authParams = {};
|
||||
if (wwwHeader && wwwHeader.length >= 1)
|
||||
authScheme = wwwHeader[1];
|
||||
if (wwwHeader && wwwHeader.length >= 3)
|
||||
authParams = www_auth_parse_params(wwwHeader[3]);
|
||||
if (typeof authParams === 'string' || authParams instanceof String) {
|
||||
$scope.authParamsError = authParams;
|
||||
} else {
|
||||
$scope.authParamsError = undefined;
|
||||
}
|
||||
var realm = authParams['realm'];
|
||||
sessionStorage.setItem("auth.realm", realm);
|
||||
if (authScheme === 'Basic' || authScheme === 'xBasic') {
|
||||
authScheme = 'Basic';
|
||||
}
|
||||
sessionStorage.setItem("auth.scheme", authScheme);
|
||||
}
|
||||
|
||||
var supportedSchemes = ['Basic', 'Bearer', 'Negotiate'];
|
||||
$scope.authSchemeSupported = supportedSchemes.includes(authScheme);
|
||||
$scope.authScheme = sessionStorage.getItem("auth.scheme");
|
||||
$scope.authRealm = sessionStorage.getItem("auth.realm");
|
||||
$scope.wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader");
|
||||
$scope.statusText = sessionStorage.getItem("auth.statusText");
|
||||
$scope.authConfig = sessionStorage.getItem("auth.config");
|
||||
$scope.authLocation = sessionStorage.getItem("auth.location");
|
||||
$scope.authLoggedinUser = sessionStorage.getItem("auth.username");
|
||||
$scope.authHeader = sessionStorage.getItem("auth.header");
|
||||
|
||||
$scope.login = function () {
|
||||
AuthenticationService.SetCredentials($scope.username, $scope.password);
|
||||
$location.path($scope.authLocation); // Redirect to the location that caused the login prompt
|
||||
};
|
||||
|
||||
$scope.logout = function() {
|
||||
// reset login status
|
||||
AuthenticationService.ClearCredentials();
|
||||
$location.path("/");
|
||||
};
|
||||
|
||||
$scope.isLoggedIn = function() {
|
||||
return (sessionStorage.getItem("auth.username") !== null);
|
||||
};
|
||||
}]);
|
||||
|
||||
// This function is copied and adapted from MIT-licensed https://github.com/randymized/www-authenticate/blob/master/lib/parsers.js
|
||||
www_auth_parse_params= function (header) {
|
||||
// This parser will definitely fail if there is more than one challenge
|
||||
var params = {};
|
||||
var tok, last_tok, _i, _len, key, value;
|
||||
var state= 0; //0: token,
|
||||
var m= header.split(/([",=])/);
|
||||
for (_i = 0, _len = m.length; _i < _len; _i++) {
|
||||
last_tok= tok;
|
||||
tok = m[_i];
|
||||
if (!tok.length) continue;
|
||||
switch (state) {
|
||||
case 0: // token
|
||||
key= tok.trim();
|
||||
state= 1; // expect equals
|
||||
continue;
|
||||
case 1: // expect equals
|
||||
if ('=' != tok) return 'Equal sign was expected after '+key;
|
||||
state= 2;
|
||||
continue;
|
||||
case 2: // expect value
|
||||
if ('"' == tok) {
|
||||
value= '';
|
||||
state= 3; // expect quoted
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
params[key]= value= tok.trim();
|
||||
state= 9; // expect comma or end
|
||||
continue;
|
||||
}
|
||||
case 3: // handling quoted string
|
||||
if ('"' == tok) {
|
||||
state= 8; // end quoted
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
value+= tok;
|
||||
state= 3; // continue accumulating quoted string
|
||||
continue;
|
||||
}
|
||||
case 8: // end quote encountered
|
||||
if ('"' == tok) {
|
||||
// double quoted
|
||||
value+= '"';
|
||||
state= 3; // back to quoted string
|
||||
continue;
|
||||
}
|
||||
if (',' == tok) {
|
||||
params[key]= value;
|
||||
state= 0;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return 'Unexpected token ('+tok+') after '+value+'"';
|
||||
}
|
||||
continue;
|
||||
case 9: // expect commma
|
||||
if (',' != tok) return 'Comma expected after '+value;
|
||||
state= 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (state) { // terminal state
|
||||
case 0: // Empty or ignoring terminal comma
|
||||
case 9: // Expecting comma or end of header
|
||||
return params;
|
||||
case 8: // Last token was end quote
|
||||
params[key]= value;
|
||||
return params;
|
||||
default:
|
||||
return 'Unexpected end of www-authenticate value.';
|
||||
}
|
||||
};
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('PluginsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Mbeans, Constants) {
|
||||
$scope.resetMenu("plugins", Constants.IS_CORE_PAGE);
|
||||
|
||||
if ($routeParams.legacytype) {
|
||||
// support legacy URLs. Angular cannot change #path without reloading controller
|
||||
$location.path("/"+$routeParams.core+"/plugins");
|
||||
$location.search("type", $routeParams.legacytype);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.refresh = function() {
|
||||
Mbeans.stats({core: $routeParams.core}, function (data) {
|
||||
var type = $location.search().type;
|
||||
$scope.types = getPluginTypes(data, type);
|
||||
$scope.type = getSelectedType($scope.types, type);
|
||||
|
||||
if ($scope.type && $routeParams.entry) {
|
||||
$scope.plugins = $routeParams.entry.split(",");
|
||||
openPlugins($scope.type, $scope.plugins);
|
||||
} else {
|
||||
$scope.plugins = [];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.selectPluginType = function(type) {
|
||||
$location.search({entry:null, type: type.lower});
|
||||
$scope.type = type;
|
||||
};
|
||||
|
||||
$scope.selectPlugin = function(plugin) {
|
||||
plugin.open = !plugin.open;
|
||||
|
||||
if (plugin.open) {
|
||||
$scope.plugins.push(plugin.name);
|
||||
} else {
|
||||
$scope.plugins.splice($scope.plugins.indexOf(plugin.name), 1);
|
||||
}
|
||||
|
||||
if ($scope.plugins.length==0) {
|
||||
$location.search("entry", null);
|
||||
} else {
|
||||
$location.search("entry", $scope.plugins.join(','));
|
||||
}
|
||||
}
|
||||
|
||||
$scope.startRecording = function() {
|
||||
$scope.isRecording = true;
|
||||
Mbeans.reference({core: $routeParams.core}, function(data) {
|
||||
$scope.reference = data.reference;
|
||||
console.log($scope.reference);
|
||||
})
|
||||
}
|
||||
|
||||
$scope.stopRecording = function() {
|
||||
$scope.isRecording = false;
|
||||
console.log($scope.reference);
|
||||
Mbeans.delta({core: $routeParams.core}, $scope.reference, function(data) {
|
||||
parseDelta($scope.types, data);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var getPluginTypes = function(data, selected) {
|
||||
var keys = [];
|
||||
var mbeans = data["solr-mbeans"];
|
||||
for (var i=0; i<mbeans.length; i+=2) {
|
||||
var key = mbeans[i];
|
||||
var lower = key.toLowerCase();
|
||||
var plugins = getPlugins(mbeans[i+1]);
|
||||
if (plugins.length == 0) continue;
|
||||
keys.push({name: key,
|
||||
selected: lower == selected,
|
||||
changes: 0,
|
||||
lower: lower,
|
||||
plugins: plugins
|
||||
});
|
||||
}
|
||||
keys.sort(function(a,b) {return a.name > b.name});
|
||||
return keys;
|
||||
};
|
||||
|
||||
var getPlugins = function(data) {
|
||||
var plugins = [];
|
||||
for (var key in data) {
|
||||
var pluginProperties = data[key];
|
||||
var stats = pluginProperties.stats;
|
||||
delete pluginProperties.stats;
|
||||
for (var stat in stats) {
|
||||
// add breaking space after a bracket or @ to handle wrap long lines:
|
||||
stats[stat] = new String(stats[stat]).replace( /([\(@])/g, '$1​');
|
||||
}
|
||||
plugin = {name: key, changed: false, stats: stats, open:false};
|
||||
plugin.properties = pluginProperties;
|
||||
plugins.push(plugin);
|
||||
}
|
||||
plugins.sort(function(a,b) {return a.name > b.name});
|
||||
return plugins;
|
||||
};
|
||||
|
||||
var getSelectedType = function(types, selected) {
|
||||
if (selected) {
|
||||
for (var i in types) {
|
||||
if (types[i].lower == selected) {
|
||||
return types[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var parseDelta = function(types, data) {
|
||||
|
||||
var getByName = function(list, name) {
|
||||
for (var i in list) {
|
||||
if (list[i].name == name) return list[i];
|
||||
}
|
||||
}
|
||||
|
||||
var mbeans = data["solr-mbeans"]
|
||||
for (var i=0; i<mbeans.length; i+=2) {
|
||||
var typeName = mbeans[i];
|
||||
var type = getByName(types, typeName);
|
||||
var plugins = mbeans[i+1];
|
||||
for (var key in plugins) {
|
||||
var changedPlugin = plugins[key];
|
||||
if (changedPlugin._changed_) {
|
||||
var plugin = getByName(type.plugins, key);
|
||||
var stats = changedPlugin.stats;
|
||||
delete changedPlugin.stats;
|
||||
plugin.properties = changedPlugin;
|
||||
for (var stat in stats) {
|
||||
// add breaking space after a bracket or @ to handle wrap long lines:
|
||||
plugin.stats[stat] = new String(stats[stat]).replace( /([\(@])/g, '$1​');
|
||||
}
|
||||
plugin.changed = true;
|
||||
type.changes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var openPlugins = function(type, selected) {
|
||||
for (var i in type.plugins) {
|
||||
var plugin = type.plugins[i];
|
||||
plugin.open = selected.indexOf(plugin.name)>=0;
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('QueryController',
|
||||
function($scope, $routeParams, $location, Query, Constants){
|
||||
$scope.resetMenu("query", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
// @todo read URL parameters into scope
|
||||
$scope.query = {q:'*:*'};
|
||||
$scope.filters = [{fq:""}];
|
||||
$scope.dismax = {defType: "dismax"};
|
||||
$scope.edismax = {defType: "edismax", stopwords: true, lowercaseOperators: false};
|
||||
$scope.hl = {hl:"on"};
|
||||
$scope.facet = {facet: "on"};
|
||||
$scope.spatial = {};
|
||||
$scope.spellcheck = {spellcheck:"on"};
|
||||
$scope.qt = "/select";
|
||||
|
||||
$scope.doQuery = function() {
|
||||
var params = {};
|
||||
|
||||
var set = function(key, value) {
|
||||
if (params[key]) {
|
||||
params[key].push(value);
|
||||
} else {
|
||||
params[key] = [value];
|
||||
}
|
||||
}
|
||||
var copy = function(params, query) {
|
||||
for (var key in query) {
|
||||
terms = query[key];
|
||||
// Booleans have no length property - only set them if true
|
||||
if (((typeof(terms) == typeof(true) && terms) || terms.length > 0) && key[0]!="$") {
|
||||
set(key, terms);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
copy(params, $scope.query);
|
||||
|
||||
if ($scope.isDismax) copy(params, $scope.dismax);
|
||||
if ($scope.isEdismax) copy(params, $scope.edismax);
|
||||
if ($scope.isHighlight) copy(params, $scope.hl);
|
||||
if ($scope.isFacet) copy(params, $scope.facet);
|
||||
if ($scope.isSpatial) copy(params, $scope.spatial);
|
||||
if ($scope.isSpellcheck) copy(params, $scope.spellcheck);
|
||||
|
||||
if ($scope.rawParams) {
|
||||
var rawParams = $scope.rawParams.split(/[&\n]/);
|
||||
for (var i in rawParams) {
|
||||
var param = rawParams[i];
|
||||
var equalPos = param.indexOf("=");
|
||||
if (equalPos > -1) {
|
||||
set(param.substring(0, equalPos), param.substring(equalPos+1));
|
||||
} else {
|
||||
set(param, ""); // Use empty value for params without "="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var qt = $scope.qt ? $scope.qt : "/select";
|
||||
|
||||
for (var filter in $scope.filters) {
|
||||
copy(params, $scope.filters[filter]);
|
||||
}
|
||||
|
||||
params.core = $routeParams.core;
|
||||
if (qt[0] == '/') {
|
||||
params.handler = qt.substring(1);
|
||||
} else { // Support legacy style handleSelect=true configs
|
||||
params.handler = "select";
|
||||
set("qt", qt);
|
||||
}
|
||||
var url = Query.url(params);
|
||||
Query.query(params, function(data) {
|
||||
$scope.lang = $scope.query.wt;
|
||||
if ($scope.lang == undefined || $scope.lang == '') {
|
||||
$scope.lang = "json";
|
||||
}
|
||||
$scope.response = data;
|
||||
// Use relative URL to make it also work through proxies that may have a different host/port/context
|
||||
$scope.url = url;
|
||||
$scope.hostPortContext = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // For display only
|
||||
});
|
||||
};
|
||||
|
||||
if ($location.search().q) {
|
||||
$scope.query.q = $location.search()["q"];
|
||||
$scope.doQuery();
|
||||
}
|
||||
|
||||
$scope.removeFilter = function(index) {
|
||||
if ($scope.filters.length === 1) {
|
||||
$scope.filters = [{fq: ""}];
|
||||
} else {
|
||||
$scope.filters.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addFilter = function(index) {
|
||||
$scope.filters.splice(index+1, 0, {fq:""});
|
||||
};
|
||||
}
|
||||
);
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('ReplicationController',
|
||||
function($scope, $rootScope, $routeParams, $interval, $timeout, Replication, Constants) {
|
||||
$scope.resetMenu("replication", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.iterationCount = 1;
|
||||
|
||||
$scope.refresh = function() {
|
||||
Replication.details({core:$routeParams.core}, function(response) {
|
||||
var timeout;
|
||||
var interval;
|
||||
if ($scope.interval) $interval.cancel($scope.interval);
|
||||
$scope.isSlave = (response.details.isSlave === 'true');
|
||||
if ($scope.isSlave) {
|
||||
$scope.progress = getProgressDetails(response.details.slave);
|
||||
$scope.iterations = getIterations(response.details.slave);
|
||||
$scope.versions = getSlaveVersions(response.details);
|
||||
$scope.settings = getSlaveSettings(response.details);
|
||||
if ($scope.settings.isReplicating) {
|
||||
timeout = $timeout($scope.refresh, 1000);
|
||||
} else if(!$scope.settings.isPollingDisabled && $scope.settings.pollInterval) {
|
||||
interval = $scope.interval = $interval(function() {
|
||||
$scope.settings.tick--;
|
||||
}, 1000, $scope.settings.tick);
|
||||
timeout = $timeout($scope.refresh, 1000*(1+$scope.settings.tick));
|
||||
}
|
||||
} else {
|
||||
$scope.versions = getMasterVersions(response.details);
|
||||
}
|
||||
$scope.master = getMasterSettings(response.details, $scope.isSlave);
|
||||
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
if (interval) $interval.cancel(interval);
|
||||
if (timeout) $timeout.cancel(timeout);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.execute = function(command) {
|
||||
Replication.command({core:$routeParams.core, command:command}, function(data){$scope.refresh()});
|
||||
}
|
||||
|
||||
$scope.showIterations = function() { $scope.iterationCount = 100000}; // limitTo should accept undefined, but doesn't work.
|
||||
$scope.hideIterations = function() { $scope.iterationCount = 1};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var getProgressDetails = function(progress) {
|
||||
|
||||
progress.timeRemaining = parseSeconds(progress.timeRemaining);
|
||||
progress.totalPercent = parseInt(progress.totalPercent);
|
||||
if (progress.totalPercent === 0) {
|
||||
progress.totalPercentWidth = "1px";
|
||||
} else {
|
||||
progress.totalPercentWidth = progress.totalPercent + "%";
|
||||
}
|
||||
progress.currentFileSizePercent = parseInt(progress.currentFileSizePercent);
|
||||
|
||||
if (!progress.indexReplicatedAtList) {
|
||||
progress.indexReplicatedAtList = [];
|
||||
}
|
||||
|
||||
if (!progress.replicationFailedAtList) {
|
||||
progress.replicationFailedAtList = [];
|
||||
}
|
||||
return progress;
|
||||
};
|
||||
|
||||
var getIterations = function(slave) {
|
||||
|
||||
var iterations = [];
|
||||
|
||||
var find = function(list, date) {
|
||||
return list.filter(function(e) {return e.date == date});
|
||||
};
|
||||
|
||||
for (var i in slave.indexReplicatedAtList) {
|
||||
var date = slave.indexReplicatedAtList[i];
|
||||
var iteration = {date:date, status:"replicated", latest: false};
|
||||
if (date == slave.indexReplicatedAt) {
|
||||
iteration.latest = true;
|
||||
}
|
||||
iterations.push(iteration);
|
||||
}
|
||||
|
||||
for (var i in slave.replicationFailedAtList) {
|
||||
var failedDate = slave.replicationFailedAtList[i];
|
||||
var matchingIterations = find(iterations, failedDate);
|
||||
if (matchingIterations[0]) {
|
||||
iteration = matchingIterations[0];
|
||||
iteration.status = "failed";
|
||||
} else {
|
||||
iteration = {date: failedDate, status:"failed", latest:false};
|
||||
iterations.push(iteration);
|
||||
}
|
||||
if (failedDate == slave.replicationFailedAt) {
|
||||
iteration.latest = true;
|
||||
}
|
||||
}
|
||||
iterations.sort(function(a,b){ return a.date> b.date;}).reverse();
|
||||
return iterations;
|
||||
};
|
||||
|
||||
var getMasterVersions = function(data) {
|
||||
versions = {masterSearch:{}, master:{}};
|
||||
|
||||
versions.masterSearch.version = data.indexVersion;
|
||||
versions.masterSearch.generation = data.generation;
|
||||
versions.masterSearch.size = data.indexSize;
|
||||
|
||||
versions.master.version = data.master.replicableVersion || '-';
|
||||
versions.master.generation = data.master.replicableGeneration || '-';
|
||||
versions.master.size = '-';
|
||||
|
||||
return versions;
|
||||
};
|
||||
|
||||
var getSlaveVersions = function(data) {
|
||||
versions = {masterSearch: {}, master: {}, slave: {}};
|
||||
|
||||
versions.slave.version = data.indexVersion;
|
||||
versions.slave.generation = data.generation;
|
||||
versions.slave.size = data.indexSize;
|
||||
|
||||
versions.master.version = data.slave.masterDetails.replicableVersion || '-';
|
||||
versions.master.generation = data.slave.masterDetails.replicableGeneration || '-';
|
||||
versions.master.size = '-';
|
||||
|
||||
versions.masterSearch.version = data.slave.masterDetails.indexVersion;
|
||||
versions.masterSearch.generation = data.slave.masterDetails.generation;
|
||||
versions.masterSearch.size = data.slave.masterDetails.indexSize;
|
||||
|
||||
versions.changedVersion = data.indexVersion !== data.slave.masterDetails.indexVersion;
|
||||
versions.changedGeneration = data.generation !== data.slave.masterDetails.generation;
|
||||
|
||||
return versions;
|
||||
};
|
||||
|
||||
var parseDateToEpoch = function(date) {
|
||||
// ["Sat Mar 03 11:00:00 CET 2012", "Sat", "Mar", "03", "11:00:00", "CET", "2012"]
|
||||
var parts = date.match( /^(\w+)\s+(\w+)\s+(\d+)\s+(\d+\:\d+\:\d+)\s+(\w+)\s+(\d+)$/ );
|
||||
|
||||
// "Sat Mar 03 2012 10:37:33"
|
||||
var d = new Date( parts[1] + ' ' + parts[2] + ' ' + parts[3] + ' ' + parts[6] + ' ' + parts[4] );
|
||||
return d.getTime();
|
||||
}
|
||||
|
||||
var parseSeconds = function(time) {
|
||||
var seconds = 0;
|
||||
var arr = new String(time || '').split('.');
|
||||
var parts = arr[0].split(':').reverse();
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
seconds += ( parseInt(parts[i], 10) || 0 ) * Math.pow(60, i);
|
||||
}
|
||||
|
||||
if (arr[1] && 5 <= parseInt(arr[1][0], 10)) {
|
||||
seconds++; // treat more or equal than .5 as additional second
|
||||
|
||||
}
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
var getSlaveSettings = function(data) {
|
||||
var settings = {};
|
||||
settings.masterUrl = data.slave.masterUrl;
|
||||
settings.isPollingDisabled = data.slave.isPollingDisabled == 'true';
|
||||
settings.pollInterval = data.slave.pollInterval;
|
||||
settings.isReplicating = data.slave.isReplicating == 'true';
|
||||
settings.nextExecutionAt = data.slave.nextExecutionAt;
|
||||
|
||||
if(settings.isReplicating) {
|
||||
settings.isApprox = true;
|
||||
settings.tick = parseSeconds(settings.pollInterval);
|
||||
} else if (!settings.isPollingDisabled && settings.pollInterval) {
|
||||
if( settings.nextExecutionAt ) {
|
||||
settings.nextExecutionAtEpoch = parseDateToEpoch(settings.nextExecutionAt);
|
||||
settings.currentTime = parseDateToEpoch(data.slave.currentDate);
|
||||
|
||||
if( settings.nextExecutionAtEpoch > settings.currentTime) {
|
||||
settings.isApprox = false;
|
||||
settings.tick = ( settings.nextExecutionAtEpoch - settings.currentTime) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
};
|
||||
|
||||
var getMasterSettings = function(details, isSlave) {
|
||||
var master = {};
|
||||
var masterData = isSlave ? details.slave.masterDetails.master : details.master;
|
||||
master.replicationEnabled = masterData.replicationEnabled == "true";
|
||||
master.replicateAfter = masterData.replicateAfter.join(", ");
|
||||
|
||||
if (masterData.confFiles) {
|
||||
master.files = [];
|
||||
var confFiles = masterData.confFiles.split(',');
|
||||
for (var i=0; i<confFiles.length; i++) {
|
||||
var file = confFiles[i];
|
||||
var short = file;
|
||||
var title = file;
|
||||
if (file.indexOf(":")>=0) {
|
||||
title = file.replace(':', ' » ');
|
||||
var parts = file.split(':');
|
||||
if (isSlave) {
|
||||
short = parts[1];
|
||||
} else {
|
||||
short = parts[0];
|
||||
}
|
||||
}
|
||||
master.files.push({title:title, name:short});
|
||||
}
|
||||
}
|
||||
return master;
|
||||
}
|
||||
+611
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
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 cookie_schema_browser_autoload = 'schema-browser_autoload';
|
||||
|
||||
solrAdminApp.controller('SchemaController',
|
||||
function($scope, $routeParams, $location, $cookies, $timeout, Luke, Constants, Schema, Config) {
|
||||
$scope.resetMenu("schema", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Luke.schema({core: $routeParams.core}, function (schema) {
|
||||
Luke.raw({core: $routeParams.core}, function (index) {
|
||||
var data = mergeIndexAndSchemaData(index, schema.schema);
|
||||
|
||||
$scope.fieldsAndTypes = getFieldsAndTypes(data);
|
||||
$scope.is = {};
|
||||
|
||||
var search = $location.search();
|
||||
leftbar = {};
|
||||
$scope.isField = $scope.isDynamicField = $scope.isType = false;
|
||||
$scope.showing = true;
|
||||
if (search.field) {
|
||||
$scope.selectedType = "Field";
|
||||
$scope.is.field = true;
|
||||
$scope.name = search.field;
|
||||
leftbar.fields = [$scope.name];
|
||||
var field = data.fields[$scope.name];
|
||||
leftbar.types = [field.type];
|
||||
if (field.dynamicBase) leftbar.dynamicFields = [field.dynamicBase];
|
||||
if (field.copySources && field.copySources.length>0) {
|
||||
leftbar.copyFieldSources = sortedObjectArray(field.copySources.sort());
|
||||
}
|
||||
if (field.copyDests && field.copyDests.length>0) {
|
||||
leftbar.copyFieldDests = sortedObjectArray(field.copyDests.sort());
|
||||
}
|
||||
$scope.fieldOrType = "field=" + $scope.name;
|
||||
} else if (search["dynamic-field"]) {
|
||||
$scope.selectedType = "Dynamic Field";
|
||||
$scope.is.dynamicField = true;
|
||||
$scope.name = search["dynamic-field"];
|
||||
leftbar.dynamicFields = [$scope.name];
|
||||
leftbar.types = [data.dynamic_fields[$scope.name].type];
|
||||
$scope.fieldOrType = "dynamic-field=" + $scope.name;
|
||||
} else if (search.type) {
|
||||
$scope.selectedType = "Type";
|
||||
$scope.is.type = true;
|
||||
$scope.name = search.type;
|
||||
leftbar.types = [$scope.name];
|
||||
leftbar.fields = filterFields("fields", data, $scope.name);
|
||||
leftbar.dynamicFields = filterFields("dynamic_fields", data, $scope.name);
|
||||
$scope.fieldOrType = "type=" + $scope.name;
|
||||
} else {
|
||||
$scope.showing = false;
|
||||
}
|
||||
$scope.leftbar = leftbar;
|
||||
$scope.core = $routeParams.core;
|
||||
$scope.uniqueKeyField = data.unique_key_field;
|
||||
$scope.similarity = data.similarity;
|
||||
if ($scope.similarity && $scope.similarity.className) {
|
||||
$scope.similarity.className = shortenPackages($scope.similarity.className);
|
||||
}
|
||||
$scope.isUniqueKeyField = ($scope.selectedType == "Field" && $scope.name == $scope.uniqueKeyField);
|
||||
|
||||
$scope.display = getFieldProperties(data, $routeParams.core, $scope.is, $scope.name);
|
||||
$scope.analysis = getAnalysisInfo(data, $scope.is, $scope.name);
|
||||
|
||||
$scope.isAutoload = $cookies[cookie_schema_browser_autoload] == "true";
|
||||
if ($scope.isAutoload) {
|
||||
$scope.toggleTerms();
|
||||
}
|
||||
|
||||
$scope.types = Object.keys(schema.schema.types);
|
||||
});
|
||||
});
|
||||
Config.get({core: $routeParams.core}, function(data) {
|
||||
$scope.isSchemaUpdatable = (data.config.hasOwnProperty('schemaFactory') == false || data.config.schemaFactory.class == "ManagedIndexSchemaFactory");
|
||||
});
|
||||
};
|
||||
$scope.refresh();
|
||||
|
||||
$scope.selectFieldOrType = function() {
|
||||
$location.search($scope.fieldOrType);
|
||||
}
|
||||
|
||||
$scope.toggleAnalyzer = function(analyzer) {
|
||||
analyzer.show = !analyzer.show;
|
||||
}
|
||||
|
||||
$scope.loadTermInfo = function() {
|
||||
var params = {fl: $scope.name, core: $routeParams.core};
|
||||
if ($scope.topTermsCount) {
|
||||
params.numTerms = $scope.topTermsCount;
|
||||
}
|
||||
$scope.isLoadingTerms = true;
|
||||
Luke.field(params, function (data) {
|
||||
$scope.isLoadingTerms = false;
|
||||
$scope.termInfo = getTermInfo(data.fields[$scope.name]);
|
||||
if (!$scope.topTermsCount) {
|
||||
$scope.topTermsCount = $scope.termInfo.termCount;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleTerms = function() {
|
||||
$scope.showTerms = !$scope.showTerms;
|
||||
|
||||
if ($scope.showTerms) {
|
||||
$scope.loadTermInfo();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.loadAllTerms = function() {
|
||||
$scope.topTermsCount = $scope.termInfo.maxTerms;
|
||||
$scope.loadTermInfo();
|
||||
}
|
||||
|
||||
$scope.toggleAutoload = function() {
|
||||
$scope.isAutoload = !$scope.isAutoload;
|
||||
$cookies[cookie_schema_browser_autoload] = $scope.isAutoload;
|
||||
console.log("cookie: " + $cookies[cookie_schema_browser_autoload]);
|
||||
}
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.showAddDynamicField = false;
|
||||
$scope.showAddCopyField = false;
|
||||
}
|
||||
|
||||
$scope.toggleAddField = function() {
|
||||
if ($scope.showAddField && $scope.adding == "field") {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddField = true;
|
||||
$scope.adding = "field";
|
||||
|
||||
$scope.newField = {
|
||||
stored: "true",
|
||||
indexed: "true",
|
||||
uninvertible: "true"
|
||||
}
|
||||
delete $scope.addErrors;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addField = function() {
|
||||
delete $scope.addErrors;
|
||||
var data = {"add-field": $scope.newField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addErrors === "string") {
|
||||
$scope.addErrors = [$scope.addErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.added = true;
|
||||
$timeout(function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.added = false;
|
||||
$scope.refresh();
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleAddDynamicField = function() {
|
||||
if ($scope.showAddField && $scope.adding == "dynamicField") {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddField = true;
|
||||
$scope.adding = "dynamicField";
|
||||
|
||||
$scope.newField = {
|
||||
stored: "true",
|
||||
indexed: "true"
|
||||
}
|
||||
delete $scope.addErrors;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addDynamicField = function() {
|
||||
delete $scope.addErrors;
|
||||
var data = {"add-dynamic-field": $scope.newField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addErrors === "string") {
|
||||
$scope.addErrors = [$scope.addErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.added = true;
|
||||
$timeout(function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.added = false;
|
||||
$scope.refresh();
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleAddCopyField = function() {
|
||||
if ($scope.showAddCopyField) {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddCopyField = true;
|
||||
|
||||
$scope.copyField = {};
|
||||
delete $scope.addCopyFieldErrors;
|
||||
}
|
||||
}
|
||||
$scope.addCopyField = function() {
|
||||
delete $scope.addCopyFieldErrors;
|
||||
var data = {"add-copy-field": $scope.copyField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addCopyFieldErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addCopyFieldErrors === "string") {
|
||||
$scope.addCopyFieldErrors = [$scope.addCopyFieldErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.showAddCopyField = false;
|
||||
$timeout($scope.refresh, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleDelete = function() {
|
||||
if ($scope.showDelete) {
|
||||
$scope.showDelete = false;
|
||||
} else {
|
||||
if ($scope.is.field) {
|
||||
$scope.deleteData = {'delete-field': {name: $scope.name}};
|
||||
} else if ($scope.is.dynamicField) {
|
||||
$scope.deleteData = {'delete-dynamic-field': {name: $scope.name}};
|
||||
} else {
|
||||
alert("TYPE NOT KNOWN");
|
||||
}
|
||||
$scope.showDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.delete = function() {
|
||||
Schema.post({core: $routeParams.core}, $scope.deleteData, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.deleteErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.deleteErrors === "string") {
|
||||
$scope.deleteErrors = [$scope.deleteErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.deleted = true;
|
||||
$timeout(function() {
|
||||
$location.search("");
|
||||
}, 1500
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.toggleDeleteCopyField = function(field) {
|
||||
field.show = !field.show;
|
||||
delete field.errors;
|
||||
}
|
||||
$scope.deleteCopyField = function(field, source, dest) {
|
||||
data = {'delete-copy-field': {source: source, dest: dest}};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
field.errors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.deleteErrors === "string") {
|
||||
field.errors = [field.errors];
|
||||
}
|
||||
} else {
|
||||
field.deleted = true;
|
||||
$timeout($scope.refresh, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var getFieldsAndTypes = function(data) {
|
||||
var fieldsAndTypes = [];
|
||||
var fields = Object.keys(data.fields).sort();
|
||||
for (var i in fields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Fields",
|
||||
value: "field=" + fields[i],
|
||||
label: fields[i]
|
||||
});
|
||||
}
|
||||
var dynamic_fields = Object.keys(data.dynamic_fields).sort();
|
||||
for (var i in dynamic_fields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Dynamic Fields",
|
||||
value: "dynamic-field=" + dynamic_fields[i],
|
||||
label: dynamic_fields[i]
|
||||
});
|
||||
}
|
||||
var types = Object.keys(data.types).sort();
|
||||
for (var i in types) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Types",
|
||||
value: "type=" + types[i],
|
||||
label: types[i]
|
||||
});
|
||||
}
|
||||
return fieldsAndTypes;
|
||||
};
|
||||
|
||||
var filterFields = function(type, data, name) {
|
||||
var fields = [];
|
||||
for (var i in data.types[name].fields) {
|
||||
var field = data.types[name].fields[i];
|
||||
if (data[type][field]) {
|
||||
fields.push(field)
|
||||
}
|
||||
}
|
||||
return fields.sort();
|
||||
}
|
||||
|
||||
var mergeIndexAndSchemaData = function(index, schema) {
|
||||
|
||||
var data = {
|
||||
unique_key_field: null,
|
||||
similarity: null,
|
||||
key: {},
|
||||
fields: {},
|
||||
dynamic_fields: {},
|
||||
types: {},
|
||||
relations: {
|
||||
f_df: {},
|
||||
f_t: {},
|
||||
df_f: {},
|
||||
df_t: {},
|
||||
t_f: {},
|
||||
t_df: {}
|
||||
}
|
||||
};
|
||||
|
||||
data.fields = index.fields;
|
||||
|
||||
data.key = index.info.key;
|
||||
|
||||
data.unique_key_field = schema.uniqueKeyField;
|
||||
data.similarity = schema.similarity;
|
||||
|
||||
data.dynamic_fields = schema.dynamicFields;
|
||||
data.types = schema.types;
|
||||
|
||||
for (var field in schema.fields) {
|
||||
data.fields[field] =
|
||||
$.extend({}, data.fields[field], schema.fields[field]);
|
||||
}
|
||||
|
||||
for (var field in data.fields) {
|
||||
var copy_dests = data.fields[field].copyDests;
|
||||
for (var i in copy_dests) {
|
||||
var copy_dest = copy_dests[i];
|
||||
if (!data.fields[copy_dest]) {
|
||||
data.fields[copy_dest] = {
|
||||
partial: true,
|
||||
copySources: []
|
||||
};
|
||||
}
|
||||
|
||||
if (data.fields[copy_dest].partial) {
|
||||
data.fields[copy_dest].copySources.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
var copy_sources = data.fields[field].copySources;
|
||||
for (var i in copy_sources) {
|
||||
var copy_source = copy_sources[i];
|
||||
if (!data.fields[copy_source]) {
|
||||
data.fields[copy_source] = {
|
||||
partial: true,
|
||||
copyDests: []
|
||||
};
|
||||
}
|
||||
|
||||
if (data.fields[copy_source].partial) {
|
||||
data.fields[copy_source].copyDests.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
data.relations.f_t[field] = data.fields[field].type;
|
||||
|
||||
if (!data.relations.t_f[data.fields[field].type]) {
|
||||
data.relations.t_f[data.fields[field].type] = [];
|
||||
}
|
||||
data.relations.t_f[data.fields[field].type].push(field);
|
||||
|
||||
if (data.fields[field].dynamicBase) {
|
||||
data.relations.f_df[field] = data.fields[field].dynamicBase;
|
||||
|
||||
if (!data.relations.df_f[data.fields[field].dynamicBase]) {
|
||||
data.relations.df_f[data.fields[field].dynamicBase] = [];
|
||||
}
|
||||
data.relations.df_f[data.fields[field].dynamicBase].push(field);
|
||||
}
|
||||
}
|
||||
|
||||
for (var dynamic_field in data.dynamic_fields) {
|
||||
data.relations.df_t[dynamic_field] = data.dynamic_fields[dynamic_field].type;
|
||||
|
||||
if (!data.relations.t_df[data.dynamic_fields[dynamic_field].type]) {
|
||||
data.relations.t_df[data.dynamic_fields[dynamic_field].type] = [];
|
||||
}
|
||||
data.relations.t_df[data.dynamic_fields[dynamic_field].type].push(dynamic_field);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
var getFieldProperties = function(data, core, is, name) {
|
||||
|
||||
var display = {};
|
||||
|
||||
display.partialState = is.field && !!data.fields[name].partial;
|
||||
|
||||
display.columns = [];
|
||||
display.rows = [];
|
||||
var allFlags = "";
|
||||
|
||||
var addRow = function(name, flags) {
|
||||
if (flags[0]!='(') {
|
||||
display.rows.push({name:name, flags:flags});
|
||||
for (var i in flags) {
|
||||
if (flags[i]!="-" && allFlags.indexOf(flags[i])<0) {
|
||||
allFlags+=flags[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
display.rows.push({name:name, comment:flags});
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the rows for our field property table
|
||||
if (is.field && data.fields[name]) {
|
||||
if (data.fields[name].flags) {
|
||||
addRow('Properties', data.fields[name].flags);
|
||||
}
|
||||
if (data.fields[name].schema) {
|
||||
addRow('Schema', data.fields[name].schema);
|
||||
}
|
||||
if (data.fields[name].index) {
|
||||
addRow('Index', data.fields[name].index);
|
||||
}
|
||||
display.docs = data.fields[name].docs;
|
||||
display.docsUrl = "#/" + core + "/query?q=" + name + ":[* TO *]";
|
||||
display.distinct = data.fields[name].distinct;
|
||||
display.positionIncrementGap = data.fields[name].positionIncrementGap;
|
||||
if (data.types[data.fields[name].type]) {
|
||||
display.similarity = data.types[data.fields[name].type].similarity;
|
||||
} else {
|
||||
display.similarity = null;
|
||||
}
|
||||
} else if (is.dynamicField && data.dynamic_fields[name] && data.dynamic_fields[name].flags) {
|
||||
addRow('Properties', data.dynamic_fields[name].flags);
|
||||
display.similarity = data.types[data.dynamic_fields[name].type].similarity;
|
||||
} else if (is.type && data.types[name]) {
|
||||
display.similarity = data.types[name].similarity;
|
||||
}
|
||||
if (display.similarity && display.similarity.className) {
|
||||
display.similarity.className = shortenPackages(display.similarity.className);
|
||||
}
|
||||
|
||||
// identify columns in field property table:
|
||||
for (var key in data.key) {
|
||||
if (allFlags.indexOf(key)>=0) {
|
||||
display.columns.push({key: key, name: data.key[key]});
|
||||
}
|
||||
}
|
||||
|
||||
// identify rows and cell values in field property table:
|
||||
for (var i in display.rows) {
|
||||
var row = display.rows[i];
|
||||
row.cells = [];
|
||||
|
||||
if (!row.flags) {
|
||||
continue; // Match the special case in the LukeRequestHandler
|
||||
}
|
||||
|
||||
for (var j in display.columns) {
|
||||
var flag = display.columns[j].key;
|
||||
row.cells.push({key: flag, value: row.flags.indexOf(flag)>=0});
|
||||
}
|
||||
}
|
||||
|
||||
return display;
|
||||
};
|
||||
|
||||
var getAnalysisInfo = function(data, is, name) {
|
||||
|
||||
var analysis = {};
|
||||
|
||||
if (is.field) {
|
||||
var type = data.relations.f_t[name];
|
||||
analysis.query = "analysis.fieldname=" + name;
|
||||
}
|
||||
else if (is.dynamicField) {
|
||||
var type = data.relations.df_t[name];
|
||||
analysis.query = "analysis.fieldtype=" + type;
|
||||
}
|
||||
else if (is.type) {
|
||||
var type = name;
|
||||
analysis.query = "analysis.fieldtype=" + name;
|
||||
}
|
||||
|
||||
var processComponentType = function (label, key, componentTypeData) {
|
||||
if (componentTypeData) {
|
||||
var components = [];
|
||||
for (var componentName in componentTypeData) {
|
||||
var componentData = componentTypeData[componentName];
|
||||
var component = {className: componentData.className, args:[]};
|
||||
if (componentData.args) {
|
||||
for (var argName in componentData.args) {
|
||||
var argValue = componentData.args[argName];
|
||||
if (argValue == "1" || argValue == "true") {
|
||||
component.args.push({name: argName, booleanValue:true});
|
||||
} else if (argValue == "0" || argValue == "false") {
|
||||
component.args.push({name: argName, booleanValue:false});
|
||||
} else {
|
||||
component.args.push({name: argName, value:argValue});
|
||||
}
|
||||
}
|
||||
}
|
||||
components.push(component);
|
||||
}
|
||||
return {label: label, key: key, components: components};
|
||||
} else {
|
||||
return {label: label, key: key};
|
||||
}
|
||||
}
|
||||
|
||||
var buildAnalyzer = function (analyzerData) {
|
||||
var analyzer = {};
|
||||
analyzer.className = analyzerData.className;
|
||||
analyzer.componentTypes = [];
|
||||
if (analyzerData.tokenizer) {
|
||||
analyzer.componentTypes.push(processComponentType("Char Filters", "charFilters", analyzerData.charFilters));
|
||||
analyzer.componentTypes.push(processComponentType("Tokenizer", "tokenizer", {tokenizer: analyzerData.tokenizer}));
|
||||
analyzer.componentTypes.push(processComponentType("Token Filters", "tokenFilters", analyzerData.filters));
|
||||
}
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
analysis.data = data.types[type];
|
||||
if (analysis.data) {
|
||||
analysis.analyzers = [
|
||||
{key: "index", name: "Index", detail: buildAnalyzer(analysis.data.indexAnalyzer)},
|
||||
{key: "query", name: "Query", detail: buildAnalyzer(analysis.data.queryAnalyzer)}
|
||||
];
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
var getTermInfo = function(data) {
|
||||
|
||||
var termInfo = {};
|
||||
if (data && data.topTerms) {
|
||||
termInfo.topTerms = [];
|
||||
|
||||
var currentGroup = {count: 0}
|
||||
for (var i = 0; i < data.topTerms.length; i += 2) {
|
||||
var count = data.topTerms[i + 1];
|
||||
if (currentGroup.count != count) {
|
||||
currentGroup = {count: count, terms: []};
|
||||
termInfo.topTerms.push(currentGroup);
|
||||
}
|
||||
currentGroup.terms.push(data.topTerms[i]);
|
||||
}
|
||||
termInfo.termCount = data.topTerms.length / 2;
|
||||
termInfo.maxTerms = data.distinct;
|
||||
}
|
||||
|
||||
if(data && data.histogram) {
|
||||
termInfo.histogram = [];
|
||||
termInfo.histogramMax = 0;
|
||||
for (var i = 0; i < data.histogram.length; i += 2) {
|
||||
termInfo.histogram.push({key: data.histogram[i], value: data.histogram[i + 1]});
|
||||
termInfo.histogramMax = Math.max(termInfo.histogramMax, data.histogram[i + 1]);
|
||||
}
|
||||
}
|
||||
return termInfo;
|
||||
};
|
||||
|
||||
var sortedObjectArray = function(list) {
|
||||
var objarr = [];
|
||||
for (var i in list) {
|
||||
objarr.push({"name": list[i]});
|
||||
}
|
||||
return objarr;
|
||||
};
|
||||
|
||||
var shortenPackages = function(className) {
|
||||
return className.replace("org.apache.solr", "o.a.s").replace("org.apache.lucene", "o.a.l");
|
||||
};
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
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 MB_FACTOR = 1024*1024;
|
||||
|
||||
solrAdminApp.controller('SegmentsController', function($scope, $routeParams, $interval, Segments, Constants) {
|
||||
$scope.resetMenu("segments", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
|
||||
Segments.get({core: $routeParams.core}, function(data) {
|
||||
var segments = data.segments;
|
||||
|
||||
var segmentSizeInBytesMax = getLargestSegmentSize(segments);
|
||||
$scope.segmentMB = Math.floor(segmentSizeInBytesMax / MB_FACTOR);
|
||||
$scope.xaxis = calculateXAxis(segmentSizeInBytesMax);
|
||||
|
||||
$scope.documentCount = 0;
|
||||
$scope.deletionCount = 0;
|
||||
|
||||
$scope.segments = [];
|
||||
for (var name in segments) {
|
||||
var segment = segments[name];
|
||||
|
||||
var segmentSizeInBytesLog = Math.log(segment.sizeInBytes);
|
||||
var segmentSizeInBytesMaxLog = Math.log(segmentSizeInBytesMax);
|
||||
|
||||
segment.totalSize = Math.floor((segmentSizeInBytesLog / segmentSizeInBytesMaxLog ) * 100);
|
||||
|
||||
segment.deletedDocSize = Math.floor((segment.delCount / segment.size) * segment.totalSize);
|
||||
if (segment.delDocSize <= 0.001) delete segment.deletedDocSize;
|
||||
|
||||
segment.aliveDocSize = segment.totalSize - segment.deletedDocSize;
|
||||
|
||||
$scope.segments.push(segment);
|
||||
|
||||
$scope.documentCount += segment.size;
|
||||
$scope.deletionCount += segment.delCount;
|
||||
}
|
||||
$scope.deletionsPercentage = calculateDeletionsPercentage($scope.documentCount, $scope.deletionCount);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleAutoRefresh = function() {
|
||||
$scope.autorefresh = !$scope.autorefresh;
|
||||
if ($scope.autorefresh) {
|
||||
$scope.interval = $interval($scope.refresh, 1000);
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
$interval.cancel($scope.interval);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
|
||||
} else if ($scope.interval) {
|
||||
$interval.cancel($scope.interval);
|
||||
}
|
||||
};
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var calculateXAxis = function(segmentInBytesMax) {
|
||||
var steps = [];
|
||||
var log = Math.log(segmentInBytesMax);
|
||||
|
||||
for (var j=0, step=log/4; j<3; j++, step+=log/4) {
|
||||
steps.push({pos:j, value:Math.floor((Math.pow(Math.E, step))/MB_FACTOR)})
|
||||
}
|
||||
return steps;
|
||||
};
|
||||
|
||||
var getLargestSegmentSize = function(segments) {
|
||||
var max = 0;
|
||||
for (var name in segments) {
|
||||
max = Math.max(max, segments[name].sizeInBytes);
|
||||
}
|
||||
return max;
|
||||
};
|
||||
|
||||
var calculateDeletionsPercentage = function(docCount, delCount) {
|
||||
if (docCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
var percent = delCount / docCount * 100;
|
||||
return Math.round(percent * 100) / 100;
|
||||
}
|
||||
};
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
solrAdminApp.controller('StreamController',
|
||||
function($scope, $routeParams, $location, Query, Constants) {
|
||||
|
||||
$scope.resetMenu("stream", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.stream = {
|
||||
wt: 'json',
|
||||
expr: $scope.expr,
|
||||
indent: 'on'
|
||||
};
|
||||
$scope.qt = "stream";
|
||||
$scope.doExplanation = false
|
||||
|
||||
$scope.doStream = function() {
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.handler = $scope.qt;
|
||||
params.expr = [$scope.expr]
|
||||
if($scope.doExplanation){
|
||||
params.explain = [$scope.doExplanation]
|
||||
}
|
||||
|
||||
$scope.lang = "json";
|
||||
$scope.response = null;
|
||||
$scope.url = "";
|
||||
|
||||
var url = Query.url(params);
|
||||
|
||||
Query.query(params, function(data) {
|
||||
|
||||
var jsonData = JSON.parse(data.toJSON().data);
|
||||
if (undefined != jsonData["explanation"]) {
|
||||
$scope.showExplanation = true;
|
||||
|
||||
streamGraphSubController($scope, jsonData["explanation"])
|
||||
delete jsonData["explanation"]
|
||||
} else {
|
||||
$scope.showExplanation = false;
|
||||
}
|
||||
|
||||
data.data = JSON.stringify(jsonData,null,2);
|
||||
|
||||
$scope.lang = "json";
|
||||
$scope.response = data;
|
||||
$scope.url = url;
|
||||
$scope.hostPortContext = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // For display only
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
if ($location.search().expr) {
|
||||
$scope.expr = $location.search()["expr"];
|
||||
$scope.doStream();
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
var streamGraphSubController = function($scope, explanation) {
|
||||
$scope.showGraph = true;
|
||||
$scope.pos = 0;
|
||||
$scope.rows = 8;
|
||||
|
||||
$scope.resetGraph = function() {
|
||||
$scope.pos = 0;
|
||||
$scope.initGraph();
|
||||
}
|
||||
|
||||
$scope.initGraph = function(explanation) {
|
||||
|
||||
data = explanation
|
||||
|
||||
var leafCount = 0;
|
||||
var maxDepth = 0;
|
||||
var rootNode = {};
|
||||
|
||||
leafCount = 0;
|
||||
|
||||
let recurse = function(dataNode, depth) {
|
||||
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
}
|
||||
|
||||
let graphNode = {
|
||||
name: dataNode.expressionNodeId,
|
||||
implementingClass: 'unknown',
|
||||
data: {}
|
||||
};
|
||||
|
||||
["expressionNodeId", "expressionType", "functionName", "implementingClass", "expression", "note", "helpers"].forEach(function(key) {
|
||||
graphNode.data[key] = dataNode[key];
|
||||
});
|
||||
|
||||
if (dataNode.children && dataNode.children.length > 0) {
|
||||
graphNode.children = [];
|
||||
dataNode.children.forEach(function(n) {
|
||||
graphNode.children.push(recurse(n, depth + 1));
|
||||
});
|
||||
} else {
|
||||
++leafCount;
|
||||
}
|
||||
|
||||
return graphNode;
|
||||
}
|
||||
|
||||
$scope.showPaging = false;
|
||||
$scope.isRadial = false;
|
||||
$scope.explanationData = recurse(data, 1);
|
||||
|
||||
$scope.depth = maxDepth + 1;
|
||||
$scope.leafCount = leafCount;
|
||||
};
|
||||
|
||||
$scope.initGraph(explanation);
|
||||
};
|
||||
|
||||
solrAdminApp.directive('explanationGraph', function(Constants) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: {
|
||||
data: "=",
|
||||
leafCount: "=",
|
||||
depth: "="
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
var helper_path_class = function(p) {
|
||||
var classes = ['link'];
|
||||
|
||||
return classes.join(' ');
|
||||
};
|
||||
|
||||
var helper_node_class = function(d) {
|
||||
var classes = ['node'];
|
||||
|
||||
if (d.data && d.data.expressionType) {
|
||||
classes.push(d.data.expressionType);
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
};
|
||||
|
||||
var helper_node_text = function(d) {
|
||||
if (d.data && d.data.functionName) {
|
||||
return d.data.functionName;
|
||||
}
|
||||
|
||||
return d.name
|
||||
};
|
||||
|
||||
var helper_tooltip = function(d) {
|
||||
|
||||
return [
|
||||
"Function: " + d.data.functionName,
|
||||
"Type: " + d.data.expressionType,
|
||||
"Class: " + d.data.implementingClass.replace("org.apache.solr.client.solrj.io", "o.a.s.c.s.i"),
|
||||
"=============",
|
||||
d.data.expression
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
scope.$watch("data", function(newValue, oldValue) {
|
||||
if (newValue) {
|
||||
flatGraph(element, scope.data, scope.depth, scope.leafCount);
|
||||
}
|
||||
});
|
||||
|
||||
var flatGraph = function(element, graphData, depth, leafCount) {
|
||||
var w = 100 + (depth * 100),
|
||||
h = leafCount * 40;
|
||||
|
||||
var tree = d3.layout.tree().size([h, w]);
|
||||
|
||||
var diagonal = d3.svg.diagonal().projection(function(d) {
|
||||
return [d.y * .7, d.x];
|
||||
});
|
||||
|
||||
d3.select('#canvas', element).html('');
|
||||
var vis = d3.select('#canvas', element).append('svg')
|
||||
.attr('width', w)
|
||||
.attr('height', h)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(25, 0)');
|
||||
|
||||
var nodes = tree.nodes(graphData);
|
||||
|
||||
var link = vis.selectAll('path.link')
|
||||
.data(tree.links(nodes))
|
||||
.enter().append('path')
|
||||
.attr('class', helper_path_class)
|
||||
.attr('d', diagonal);
|
||||
|
||||
var node = vis.selectAll('g.node')
|
||||
.data(nodes)
|
||||
.enter().append('g')
|
||||
.attr('class', helper_node_class)
|
||||
.attr('transform', function(d) {
|
||||
return 'translate(' + d.y * .7 + ',' + d.x + ')';
|
||||
})
|
||||
|
||||
node.append('circle')
|
||||
.attr('r', 4.5);
|
||||
|
||||
node.append('title')
|
||||
.text(helper_tooltip);
|
||||
|
||||
node.append('text')
|
||||
.attr('dx', function(d) {
|
||||
return 8;
|
||||
})
|
||||
.attr('dy', function(d) {
|
||||
return 5;
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
return 'start';
|
||||
})
|
||||
.text(helper_node_text)
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('ThreadsController',
|
||||
function($scope, Threads, Constants){
|
||||
$scope.resetMenu("threads", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Threads.get(function(data) {
|
||||
var threadDump = data.system.threadDump;
|
||||
var threads = [];
|
||||
for (var i=1; i<threadDump.length; i+=2) {
|
||||
var thread = threadDump[i];
|
||||
if (!!thread.stackTrace) {
|
||||
var stackTrace = [];
|
||||
for (var j=0; j<thread.stackTrace.length; j++) {
|
||||
var trace = thread.stackTrace[j].replace("(", "\u200B("); // allow wrapping to happen, \u200B is a zero-width space
|
||||
stackTrace.push({id:thread.id + ":" + j, trace: trace});
|
||||
}
|
||||
thread.stackTrace = stackTrace;
|
||||
}
|
||||
threads.push(thread);
|
||||
}
|
||||
$scope.threads = threads;
|
||||
});
|
||||
};
|
||||
$scope.toggleStacktrace = function(thread) {
|
||||
thread.showStackTrace = !thread.showStackTrace;
|
||||
};
|
||||
$scope.toggleStacktraces = function() {
|
||||
$scope.showAllStacktraces = !$scope.showAllStacktraces;
|
||||
for (var i=0; i<$scope.threads.length; i++) {
|
||||
$scope.threads[i].showStackTrace = $scope.showAllStacktraces;
|
||||
}
|
||||
};
|
||||
$scope.refresh();
|
||||
});
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
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 solrAdminServices = angular.module('solrAdminServices', ['ngResource']);
|
||||
|
||||
solrAdminServices.factory('System',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/info/system', {"wt":"json", "nodes": "@nodes", "_":Date.now()});
|
||||
}])
|
||||
.factory('Metrics',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/metrics', {"wt":"json", "nodes": "@nodes", "prefix":"@prefix", "_":Date.now()});
|
||||
}])
|
||||
.factory('Collections',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/collections',
|
||||
{'wt':'json', '_':Date.now()}, {
|
||||
"list": {params:{action: "LIST"}},
|
||||
"status": {params:{action: "CLUSTERSTATUS"}},
|
||||
"add": {params:{action: "CREATE"}},
|
||||
"delete": {params:{action: "DELETE"}},
|
||||
"rename": {params:{action: "RENAME"}},
|
||||
"createAlias": {params:{action: "CREATEALIAS"}},
|
||||
"deleteAlias": {params:{action: "DELETEALIAS"}},
|
||||
"deleteReplica": {params:{action: "DELETEREPLICA"}},
|
||||
"addReplica": {params:{action: "ADDREPLICA"}},
|
||||
"deleteShard": {params:{action: "DELETESHARD"}},
|
||||
"reload": {method: "GET", params:{action:"RELOAD", core: "@core"}}
|
||||
});
|
||||
}])
|
||||
.factory('Cores',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/cores',
|
||||
{'wt':'json', '_':Date.now()}, {
|
||||
"query": {},
|
||||
"list": {params:{indexInfo: false}},
|
||||
"add": {params:{action: "CREATE"}},
|
||||
"unload": {params:{action: "UNLOAD", core: "@core"}},
|
||||
"rename": {params:{action: "RENAME"}},
|
||||
"swap": {params:{action: "SWAP"}},
|
||||
"reload": {method: "GET", params:{action:"RELOAD", core: "@core"}, headers:{doNotIntercept: "true"}}
|
||||
});
|
||||
}])
|
||||
.factory('Logging',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/info/logging', {'wt':'json', '_':Date.now()}, {
|
||||
"events": {params: {since:'0'}},
|
||||
"levels": {},
|
||||
"setLevel": {}
|
||||
});
|
||||
}])
|
||||
.factory('Zookeeper',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/zookeeper', {wt:'json', _:Date.now()}, {
|
||||
"simple": {},
|
||||
"liveNodes": {params: {path: '/live_nodes'}},
|
||||
"clusterState": {params: {detail: "true", path: "/clusterstate.json"}},
|
||||
"detail": {params: {detail: "true", path: "@path"}},
|
||||
"configs": {params: {detail:false, path: "/configs/"}},
|
||||
"aliases": {params: {detail: "true", path: "/aliases.json"}, transformResponse:function(data) {
|
||||
var znode = $.parseJSON(data).znode;
|
||||
if (znode.data) {
|
||||
return {aliases: $.parseJSON(znode.data).collection};
|
||||
} else {
|
||||
return {aliases: {}};
|
||||
}
|
||||
}}
|
||||
});
|
||||
}])
|
||||
.factory('ZookeeperStatus',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/zookeeper/status', {wt:'json', _:Date.now()}, {
|
||||
"monitor": {}
|
||||
});
|
||||
}])
|
||||
.factory('Properties',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/info/properties', {'wt':'json', '_':Date.now()});
|
||||
}])
|
||||
.factory('Threads',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/info/threads', {'wt':'json', '_':Date.now()});
|
||||
}])
|
||||
.factory('Properties',
|
||||
['$resource', function($resource) {
|
||||
return $resource('admin/info/properties', {'wt':'json', '_':Date.now()});
|
||||
}])
|
||||
.factory('Replication',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/replication', {'wt':'json', core: "@core", '_':Date.now()}, {
|
||||
"details": {params: {command: "details"}},
|
||||
"command": {params: {}}
|
||||
});
|
||||
}])
|
||||
.factory('CoreSystem',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/system', {wt:'json', core: "@core", _:Date.now()});
|
||||
}])
|
||||
.factory('Update',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/:handler', {core: '@core', wt:'json', _:Date.now(), handler:'update'}, {
|
||||
"commit": {params: {commit: "true"}},
|
||||
"post": {headers: {'Content-type': 'application/json'}, method: "POST", params: {handler: '@handler'}},
|
||||
"postJson": {headers: {'Content-type': 'application/json'}, method: "POST", params: {handler: '@handler'}},
|
||||
"postXml": {headers: {'Content-type': 'text/xml'}, method: "POST", params: {handler: '@handler'}},
|
||||
"postCsv": {headers: {'Content-type': 'application/csv'}, method: "POST", params: {handler: '@handler'}}
|
||||
});
|
||||
}])
|
||||
.service('FileUpload', function ($http) {
|
||||
this.upload = function(params, file, success, error){
|
||||
var url = "" + params.core + "/" + params.handler + "?";
|
||||
raw = params.raw;
|
||||
delete params.core;
|
||||
delete params.handler;
|
||||
delete params.raw;
|
||||
url += $.param(params);
|
||||
if (raw && raw.length>0) {
|
||||
if (raw[0] != "&") raw = "&" + raw;
|
||||
url += raw;
|
||||
}
|
||||
var fd = new FormData();
|
||||
fd.append('file', file);
|
||||
$http.post(url, fd, {
|
||||
transformRequest: angular.identity,
|
||||
headers: {'Content-Type': undefined}
|
||||
}).success(success).error(error);
|
||||
}
|
||||
})
|
||||
.factory('Luke',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/luke', {core: '@core', wt:'json', _:Date.now()}, {
|
||||
"index": {params: {numTerms: 0, show: 'index'}},
|
||||
"raw": {params: {numTerms: 0}},
|
||||
"schema": {params: {show:'schema'}},
|
||||
"field": {},
|
||||
"fields": {params: {show:'schema'}, interceptor: {
|
||||
response: function(response) {
|
||||
var fieldsAndTypes = [];
|
||||
for (var field in response.data.schema.fields) {
|
||||
fieldsAndTypes.push({group: "Fields", label: field, value: "fieldname=" + field});
|
||||
}
|
||||
for (var type in response.data.schema.types) {
|
||||
fieldsAndTypes.push({group: "Types", label: type, value: "fieldtype=" + type});
|
||||
}
|
||||
return fieldsAndTypes;
|
||||
}
|
||||
}}
|
||||
});
|
||||
}])
|
||||
.factory('Analysis',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/analysis/field', {core: '@core', wt:'json', _:Date.now()}, {
|
||||
"field": {params: {"analysis.showmatch": true}}
|
||||
});
|
||||
}])
|
||||
.factory('DataImport',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/:name', {core: '@core', name: '@name', indent:'on', wt:'json', _:Date.now()}, {
|
||||
"config": {params: {command: "show-config"}, headers: {doNotIntercept: "true"},
|
||||
transformResponse: function(data) {
|
||||
return {config: data};
|
||||
}
|
||||
},
|
||||
"status": {params: {command: "status"}, headers: {doNotIntercept: "true"}},
|
||||
"reload": {params: {command: "reload-config"}},
|
||||
"post": {method: "POST",
|
||||
headers: {'Content-type': 'application/x-www-form-urlencoded'},
|
||||
transformRequest: function(data) { return $.param(data) }}
|
||||
});
|
||||
}])
|
||||
.factory('Ping',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/ping', {wt:'json', core: '@core', ts:Date.now(), _:Date.now()}, {
|
||||
"ping": {},
|
||||
"status": {params:{action:"status"}, headers: {doNotIntercept: "true"}
|
||||
}});
|
||||
}])
|
||||
.factory('Mbeans',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/mbeans', {'wt':'json', core: '@core', '_':Date.now()}, {
|
||||
stats: {params: {stats: true}},
|
||||
info: {},
|
||||
reference: {
|
||||
params: {wt: "xml", stats: true}, transformResponse: function (data) {
|
||||
return {reference: data}
|
||||
}
|
||||
},
|
||||
delta: {method: "POST",
|
||||
params: {stats: true, diff:true},
|
||||
headers: {'Content-type': 'application/x-www-form-urlencoded'},
|
||||
transformRequest: function(data) {
|
||||
return "stream.body=" + encodeURIComponent(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}])
|
||||
.factory('Files',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/file', {'wt':'json', core: '@core', '_':Date.now()}, {
|
||||
"list": {},
|
||||
"get": {method: "GET", interceptor: {
|
||||
response: function(config) {return config;}
|
||||
}, transformResponse: function(data) {
|
||||
return data;
|
||||
}}
|
||||
});
|
||||
}])
|
||||
.factory('Query',
|
||||
['$resource', function($resource) {
|
||||
var resource = $resource(':core/:handler', {core: '@core', handler: '@handler', '_':Date.now()}, {
|
||||
"query": {
|
||||
method: "GET",
|
||||
transformResponse: function (data) {
|
||||
return {data: data}
|
||||
},
|
||||
headers: {doNotIntercept: "true"}
|
||||
}
|
||||
});
|
||||
resource.url = function(params) {
|
||||
var qs = [];
|
||||
for (key in params) {
|
||||
if (key != "core" && key != "handler") {
|
||||
for (var i in params[key]) {
|
||||
qs.push(key + "=" + encodeURIComponent(params[key][i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return "" + params.core + "/" + params.handler + "?" + qs.sort().join("&");
|
||||
}
|
||||
return resource;
|
||||
}])
|
||||
.factory('Segments',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/admin/segments', {'wt':'json', core: '@core', _:Date.now()}, {
|
||||
get: {}
|
||||
});
|
||||
}])
|
||||
.factory('Schema',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/schema', {wt: 'json', core: '@core', _:Date.now()}, {
|
||||
get: {method: "GET"},
|
||||
check: {method: "GET", headers: {doNotIntercept: "true"}},
|
||||
post: {method: "POST"}
|
||||
});
|
||||
}])
|
||||
.factory('Config',
|
||||
['$resource', function($resource) {
|
||||
return $resource(':core/config', {wt: 'json', core: '@core', _:Date.now()}, {
|
||||
get: {method: "GET"}
|
||||
})
|
||||
}])
|
||||
.factory('AuthenticationService',
|
||||
['base64', function (base64) {
|
||||
var service = {};
|
||||
|
||||
service.SetCredentials = function (username, password) {
|
||||
var authdata = base64.encode(username + ':' + password);
|
||||
|
||||
sessionStorage.setItem("auth.header", "Basic " + authdata);
|
||||
sessionStorage.setItem("auth.username", username);
|
||||
};
|
||||
|
||||
service.ClearCredentials = function () {
|
||||
sessionStorage.removeItem("auth.header");
|
||||
sessionStorage.removeItem("auth.scheme");
|
||||
sessionStorage.removeItem("auth.realm");
|
||||
sessionStorage.removeItem("auth.username");
|
||||
sessionStorage.removeItem("auth.wwwAuthHeader");
|
||||
sessionStorage.removeItem("auth.statusText");
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
||||
Посилання в новій задачі
Заблокувати користувача