mirror of https://github.com/apache/lucene.git
SOLR-7279: Add plugins/stats tab support to Angular Admin UI
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1671283 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7092d9a022
commit
ff10738cba
|
@ -0,0 +1,72 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<div id="plugins" class="clearfix">
|
||||
|
||||
<div id="frame">
|
||||
<ul>
|
||||
<li class="entry" ng-class="{changed: plugin.changed}" ng-repeat="plugin in type.plugins">
|
||||
<a ng-click="selectPlugin(plugin)">
|
||||
<span>{{ plugin.name }}</span>
|
||||
</a>
|
||||
<ul class="detail" ng-show="plugin.open">
|
||||
<li ng-repeat="(key, value) in plugin.properties" ng-class="{odd: $odd}">
|
||||
<dl class="clearfix">
|
||||
<dt>{{ key }}:</dt>
|
||||
<!--<dd ng-repeat="v in value">{{v}}</dd><!-- is AN ARRAY!!-->
|
||||
<dd>{{value}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="stats clearfix" ng-show="plugin.stats">
|
||||
<span>stats:</span>
|
||||
<ul>
|
||||
<li ng-repeat="(key, value) in plugin.stats" ng-class="{odd: $odd}">
|
||||
<dl class="clearfix">
|
||||
<dt>{{key}}:</dt>
|
||||
<dd>{{value}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="navigation" class="clearfix">
|
||||
|
||||
<ul>
|
||||
<li ng-repeat="type in types" class="{{type.lower}}">
|
||||
<a ng-click="selectPluginType(type)" rel="{{type.name}}">{{type.name}}
|
||||
<span ng-show="type.changes">{{type.changes}}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="PLUGINCHANGES"><a ng-click="startRecording()">Watch Changes</a></li>
|
||||
<li class="RELOAD"><a ng-click="refresh()">Refresh Values</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="recording" ng-show="isRecording">
|
||||
<div class="wrapper clearfix">
|
||||
|
||||
<p class="loader">Watching for Changes</p>
|
||||
<button class="primary" ng-click="stopRecording()">Stop & Show Changes</button>
|
||||
|
||||
</div>
|
||||
<div id="blockUI"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#content #plugins #navigation
|
||||
{
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#content #plugins #navigation .cache a { background-image: url( ../../img/ico/disk-black.png ); }
|
||||
#content #plugins #navigation .core a { background-image: url( ../../img/ico/wooden-box.png ); }
|
||||
#content #plugins #navigation .other a { background-image: url( ../../img/ico/zone.png ); }
|
||||
#content #plugins #navigation .highlighting a { background-image: url( ../../img/ico/highlighter-text.png ); }
|
||||
#content #plugins #navigation .updatehandler a{ background-image: url( ../../img/ico/arrow-circle.png ); }
|
||||
#content #plugins #navigation .queryhandler a { background-image: url( ../../img/ico/magnifier.png ); }
|
||||
#content #plugins #navigation .queryparser a { background-image: url( ../../img/ico/asterisk.png ); }
|
||||
|
||||
#content #plugins #navigation .PLUGINCHANGES { margin-top: 20px; }
|
||||
#content #plugins #navigation .PLUGINCHANGES a { background-image: url( ../../img/ico/eye.png ); }
|
||||
#content #plugins #navigation .RELOAD a { background-image: url( ../../img/ico/arrow-circle.png ); }
|
||||
|
||||
|
||||
#content #plugins #navigation a
|
||||
{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#content #plugins #navigation a span
|
||||
{
|
||||
background-color: #bba500;
|
||||
border-radius: 5px;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
line-height: 1.4em;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
#content #plugins #frame
|
||||
{
|
||||
float: right;
|
||||
width: 78%;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry
|
||||
{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry:last-child
|
||||
{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry a
|
||||
{
|
||||
background-image: url( ../../img/ico/chevron-small-expand.png );
|
||||
background-position: 0 50%;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
padding-left: 21px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry.changed a span
|
||||
{
|
||||
color: #bba500;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry.expanded a
|
||||
{
|
||||
background-image: url( ../../img/ico/chevron-small.png );
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry.expanded ul
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry ul
|
||||
{
|
||||
border-left: 9px solid #f0f3ff;
|
||||
margin-left: 3px;
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry li
|
||||
{
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry li.stats
|
||||
{
|
||||
border-top: 1px solid #c0c0c0;
|
||||
margin-top: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry li.odd
|
||||
{
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry dt,
|
||||
#content #plugins #frame .entry .stats span
|
||||
{
|
||||
float: left;
|
||||
width: 11%;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry dd,
|
||||
#content #plugins #frame .entry .stats ul
|
||||
{
|
||||
float: right;
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry .stats ul
|
||||
{
|
||||
border-left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry .stats dt
|
||||
{
|
||||
width: 27%;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry .stats dd
|
||||
{
|
||||
width: 72%;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry.expanded a.linker {
|
||||
background-image: none;
|
||||
background-position: 0 0;
|
||||
display: inline;
|
||||
font-weight: normal;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
#content #plugins #frame .entry.expanded a.linker:hover {
|
||||
background-color:#F0F3FF;
|
||||
}
|
||||
|
||||
#recording #blockUI
|
||||
{
|
||||
position: absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
opacity: 0.6;
|
||||
z-index:1000;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#recording .wrapper
|
||||
{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
padding: 30px;
|
||||
width: 415px;
|
||||
height: 100px;
|
||||
border: 2px solid black;
|
||||
background-color: #FFF;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#recording p
|
||||
{
|
||||
background-position: 0 50%;
|
||||
float: left;
|
||||
padding-left: 21px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
#recording button
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
#recording button span
|
||||
{
|
||||
background-image: url( ../../img/ico/new-text.png );
|
||||
}
|
|
@ -34,7 +34,7 @@ limitations under the License.
|
|||
<link rel="stylesheet" type="text/css" href="css/styles/java-properties.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/logging.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/menu.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/styles/plugins.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/plugins.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/documents.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/query.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/styles/replication.css?_=${version}">
|
||||
|
@ -66,6 +66,7 @@ limitations under the License.
|
|||
<script src="js/angular/controllers/documents.js"></script>
|
||||
<script src="js/angular/controllers/files.js"></script>
|
||||
<script src="js/angular/controllers/query.js"></script>
|
||||
<script src="js/angular/controllers/plugins.js"></script>
|
||||
|
||||
</head>
|
||||
<body ng-controller="MainController">
|
||||
|
|
|
@ -75,6 +75,16 @@ solrAdminApp.config([
|
|||
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'
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
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) {
|
||||
$scope.resetMenu("plugins");
|
||||
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -125,7 +125,21 @@ solrAdminServices.factory('System',
|
|||
}])
|
||||
.factory('Mbeans',
|
||||
['$resource', function($resource) {
|
||||
return $resource('/solr/:core/admin/mbeans', {'wt':'json', 'stats': true, '_':Date.now()}); // @core
|
||||
return $resource('/solr/:core/admin/mbeans', {'wt':'json', core: '@core', '_':Date.now()}, {
|
||||
stats: {params: {stats: true}},
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue