mirror of https://github.com/apache/lucene.git
SOLR-4316 add a collections dropdown alongside cores dropdown
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1698459 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e6e4f18fac
commit
3da81fb200
|
@ -137,6 +137,8 @@ New Features
|
|||
|
||||
* SOLR-7789: Introduce a ConfigSet management API (Gregory Chanan)
|
||||
|
||||
* SOLR-4316: Add a collections dropdown to angular admin UI (Upayavira, Shalin Shekhar Mangar)
|
||||
|
||||
Bug Fixes
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
|
||||
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 #dashboard .block
|
||||
{
|
||||
background-image: none;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist
|
||||
{
|
||||
float: left;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist dt,
|
||||
#content #dashboard .fieldlist dd
|
||||
{
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist dt
|
||||
{
|
||||
clear: left;
|
||||
margin-right: 2%;
|
||||
text-align: right;
|
||||
width: 23%;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist dd
|
||||
{
|
||||
width: 74%;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist .index_optimized
|
||||
{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist .ico
|
||||
{
|
||||
background-image: url( ../../img/ico/slash.png );
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist .ico.ico-1
|
||||
{
|
||||
background-image: url( ../../img/ico/tick.png );
|
||||
}
|
||||
|
||||
#content #dashboard .fieldlist .ico span
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content #dashboard #statistics .index_optimized.value a
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content #dashboard #statistics .index_optimized.value.ico-0 a
|
||||
{
|
||||
background-color: #f0f0f0;
|
||||
background-image: url( ../../img/ico/hammer-screwdriver.png );
|
||||
background-position: 5px 50%;
|
||||
border: 1px solid #c0c0c0;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 50px;
|
||||
padding: 1px 5px;
|
||||
padding-left: 26px;
|
||||
}
|
||||
|
||||
#content #dashboard #statistics .index_has-deletions
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content #dashboard #statistics .index_has-deletions.value.ico-0
|
||||
{
|
||||
background-image: url( ../../img/ico/tick-red.png );
|
||||
}
|
||||
|
||||
#content #dashboard #replication
|
||||
{
|
||||
float: left;
|
||||
}
|
||||
|
||||
#content #dashboard #replication .is-replicating
|
||||
{
|
||||
background-position: 99% 50%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content #dashboard #replication #details table thead td span
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content #dashboard #instance
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
#content #dashboard #instance .dir_impl
|
||||
{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#content #dashboard #admin-extra
|
||||
{
|
||||
float: left;
|
||||
}
|
||||
|
||||
#content #dashboard #healthcheck
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
#content #dashboard #healthcheck .ico
|
||||
{
|
||||
background-image: url( ../../img/ico/slash.png );
|
||||
height: 20px;
|
||||
padding-left: 20px;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#content #dashboard #healthcheck .ico.ico-1
|
||||
{
|
||||
background-image: url( ../../img/ico/tick.png );
|
||||
}
|
||||
|
||||
#content #dashboard #system h2 { background-image: url( ../../img/ico/server.png ); }
|
||||
#content #dashboard #statistics h2 { background-image: url( ../../img/ico/chart.png ); }
|
||||
#content #dashboard #replication h2 { background-image: url( ../../img/ico/node.png ); }
|
||||
#content #dashboard #replication.master h2 { background-image: url( ../../img/ico/node-master.png ); }
|
||||
#content #dashboard #replication.slave h2 { background-image: url( ../../img/ico/node-slave.png ); }
|
||||
#content #dashboard #instance h2 { background-image: url( ../../img/ico/server.png ); }
|
||||
#content #dashboard #admin-extra h2 { background-image: url( ../../img/ico/plus-button.png ); }
|
||||
#content #dashboard #collection h2 { background-image: url( ../../img/ico/book-open-text.png ); }
|
||||
#content #dashboard #shards h2 { background-image: url( ../../img/ico/documents-stack.png ); }
|
||||
|
||||
#content #dashboard #shards { margin-left: 20px;}
|
||||
|
||||
#dashboard #shards .shard h3.shard-title {
|
||||
display: block;
|
||||
background-color: #c8c8c8;
|
||||
font-weight: bold;
|
||||
padding: 3px;
|
||||
padding-left: 30px;
|
||||
margin-left: 20px;
|
||||
margin-top: 20px;
|
||||
background-image: url( ../../img/ico/document-text.png );
|
||||
background-position-x: 10px;
|
||||
background-position-y: 3px;
|
||||
}
|
||||
|
||||
#dashboard #shards .shard .shard-detail {
|
||||
margin-bottom: 25px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
#dashboard #shards .shard .replica {
|
||||
background-color: #e4e4e4;
|
||||
}
|
||||
|
||||
#dashboard #shards .shard .replica.odd {
|
||||
background-color: #fff;
|
||||
}
|
|
@ -43,29 +43,33 @@ limitations under the License.
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#core-selector
|
||||
#core-selector,#collection-selector
|
||||
{
|
||||
margin-top: 20px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#core-selector a
|
||||
#core-selector a,
|
||||
#collection-selector a
|
||||
{
|
||||
padding: 0;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
#core-selector select
|
||||
#core-selector select,
|
||||
#collection-selector select
|
||||
{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#core-selector #has-no-cores a
|
||||
#core-selector #has-no-cores a,
|
||||
#collection-selector #has-no-collections a
|
||||
{
|
||||
background-image: url( ../../img/ico/database--plus.png );
|
||||
}
|
||||
|
||||
#core-selector #has-no-cores span
|
||||
#core-selector #has-no-cores span,
|
||||
#collection-selector #has-no-collections span
|
||||
{
|
||||
color: #c0c0c0;
|
||||
display: block;
|
||||
|
@ -172,34 +176,34 @@ limitations under the License.
|
|||
{
|
||||
}
|
||||
|
||||
#core-menu p
|
||||
.sub-menu p
|
||||
{
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
#core-menu li:first-child p
|
||||
.sub-menu li:first-child p
|
||||
{
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#core-menu p a
|
||||
.sub-menu p a
|
||||
{
|
||||
background-image: url( ../../img/ico/status-offline.png );
|
||||
}
|
||||
|
||||
#core-menu .active p a
|
||||
.sub-menu .active p a
|
||||
{
|
||||
background-image: url( ../../img/ico/box.png );
|
||||
}
|
||||
|
||||
#core-menu ul,
|
||||
.sub-menu ul,
|
||||
#menu ul
|
||||
{
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#core-menu .active ul,
|
||||
.sub-menu .active ul,
|
||||
#menu .active ul
|
||||
{
|
||||
display: block;
|
||||
|
@ -211,6 +215,7 @@ limitations under the License.
|
|||
}
|
||||
|
||||
#core-menu ul li a,
|
||||
#collection-menu ul li a,
|
||||
#menu ul li a
|
||||
{
|
||||
background-position: 7px 50%;
|
||||
|
@ -220,20 +225,20 @@ limitations under the License.
|
|||
padding-left: 26px;
|
||||
}
|
||||
|
||||
#core-menu ul li:last-child a,
|
||||
.sub-menu ul li:last-child a,
|
||||
#menu ul li:last-child a
|
||||
{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
#core-menu ul li a:hover,
|
||||
.sub-menu ul li a:hover,
|
||||
#menu ul li a:hover
|
||||
{
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#core-menu ul li.active a,
|
||||
.sub-menu ul li.active a,
|
||||
#menu ul li.active a
|
||||
{
|
||||
background-color: #d0d0d0;
|
||||
|
@ -258,7 +263,7 @@ limitations under the License.
|
|||
#menu #cloud.global .rgraph a { background-image: url( ../../img/ico/asterisk.png ); }
|
||||
#menu #cloud.global .dump a { background-image: url( ../../img/ico/download-cloud.png ); }
|
||||
|
||||
#core-menu .ping.error a
|
||||
.sub-menu .ping.error a
|
||||
{
|
||||
|
||||
background-color: #ffcccc;
|
||||
|
@ -267,19 +272,19 @@ limitations under the License.
|
|||
cursor: help;
|
||||
}
|
||||
|
||||
#core-menu .overview a { background-image: url( ../../img/ico/home.png ); }
|
||||
#core-menu .query a { background-image: url( ../../img/ico/magnifier.png ); }
|
||||
#core-menu .analysis a { background-image: url( ../../img/ico/funnel.png ); }
|
||||
#core-menu .documents a { background-image: url( ../../img/ico/documents-stack.png ); }
|
||||
#core-menu .files a { background-image: url( ../../img/ico/folder.png ); }
|
||||
#core-menu .schema-browser a { background-image: url( ../../img/ico/book-open-text.png ); }
|
||||
#core-menu .replication a { background-image: url( ../../img/ico/node.png ); }
|
||||
#core-menu .distribution a { background-image: url( ../../img/ico/node-select.png ); }
|
||||
#core-menu .ping a { background-image: url( ../../img/ico/system-monitor.png ); }
|
||||
#core-menu .logging a { background-image: url( ../../img/ico/inbox-document-text.png ); }
|
||||
#core-menu .plugins a { background-image: url( ../../img/ico/block.png ); }
|
||||
#core-menu .dataimport a { background-image: url( ../../img/ico/document-import.png ); }
|
||||
#core-menu .segments a { background-image: url( ../../img/ico/construction.png ); }
|
||||
.sub-menu .overview a { background-image: url( ../../img/ico/home.png ); }
|
||||
.sub-menu .query a { background-image: url( ../../img/ico/magnifier.png ); }
|
||||
.sub-menu .analysis a { background-image: url( ../../img/ico/funnel.png ); }
|
||||
.sub-menu .documents a { background-image: url( ../../img/ico/documents-stack.png ); }
|
||||
.sub-menu .files a { background-image: url( ../../img/ico/folder.png ); }
|
||||
.sub-menu .schema-browser a { background-image: url( ../../img/ico/book-open-text.png ); }
|
||||
.sub-menu .replication a { background-image: url( ../../img/ico/node.png ); }
|
||||
.sub-menu .distribution a { background-image: url( ../../img/ico/node-select.png ); }
|
||||
.sub-menu .ping a { background-image: url( ../../img/ico/system-monitor.png ); }
|
||||
.sub-menu .logging a { background-image: url( ../../img/ico/inbox-document-text.png ); }
|
||||
.sub-menu .plugins a { background-image: url( ../../img/ico/block.png ); }
|
||||
.sub-menu .dataimport a { background-image: url( ../../img/ico/document-import.png ); }
|
||||
.sub-menu .segments a { background-image: url( ../../img/ico/construction.png ); }
|
||||
|
||||
|
||||
#content #navigation
|
||||
|
|
|
@ -27,7 +27,7 @@ limitations under the License.
|
|||
<link rel="stylesheet" type="text/css" href="css/angular/analysis.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/cloud.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/cores.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/styles/dashboard.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/dashboard.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/dataimport.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/files.css?_=${version}">
|
||||
<link rel="stylesheet" type="text/css" href="css/angular/index.css?_=${version}">
|
||||
|
@ -64,6 +64,7 @@ limitations under the License.
|
|||
<script src="js/angular/controllers/threads.js"></script>
|
||||
<script src="js/angular/controllers/java-properties.js"></script>
|
||||
<script src="js/angular/controllers/core-overview.js"></script>
|
||||
<script src="js/angular/controllers/collection-overview.js"></script>
|
||||
<script src="js/angular/controllers/analysis.js"></script>
|
||||
<script src="js/angular/controllers/dataimport.js"></script>
|
||||
<script src="js/angular/controllers/documents.js"></script>
|
||||
|
@ -155,11 +156,36 @@ limitations under the License.
|
|||
|
||||
</ul>
|
||||
|
||||
<div id="collection-selector" ng-show="isCloudEnabled">
|
||||
<div id="has-collections" ng-show="collections.length!=0">
|
||||
<select data-placeholder="Collection Selector"
|
||||
ng-model="currentCollection"
|
||||
chosen
|
||||
ng-change="showCollection(currentCollection)"
|
||||
ng-options="collection.name for collection in collections"></select>
|
||||
</div>
|
||||
<p id="has-no-collections" ng-show="collections.length==0"><a href="#/~collections">
|
||||
No collections available
|
||||
<span>Go and create one</span>
|
||||
</a></p>
|
||||
</div>
|
||||
<div id="collection-menu" class="sub-menu" ng-show="currentCollection">
|
||||
<ul>
|
||||
<li class="overview" ng-class="{active:page=='collection-overview'}"><a href="#/{{currentCore.name}}/collection-overview"><span>Overview</span></a></li>
|
||||
<li class="analysis" ng-class="{active:page=='analysis'}"><a href="#/{{currentCollection.name}}/analysis"><span>Analysis</span></a></li>
|
||||
<li class="dataimport" ng-class="{active:page=='dataimport'}"><a href="#/{{currentCollection.name}}/dataimport"><span>Dataimport</span></a></li>
|
||||
<li class="documents" ng-class="{active:page=='documents'}"><a href="#/{{currentCollection.name}}/documents"><span>Documents</span></a></li>
|
||||
<li class="files" ng-class="{active:page=='files'}"><a href="#/{{currentCollection.name}}/files"><span>Files</span></a></li>
|
||||
<li class="query" ng-class="{active:page=='query'}"><a href="#/{{currentCollection.name}}/query"><span>Query</span></a></li>
|
||||
<li class="schema-browser" ng-class="{active:page=='schema-browser'}"><a href="#/{{currentCollection.name}}/schema-browser"><span>Schema Browser</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="core-selector">
|
||||
<div id="has-cores" ng-show="cores.length!=0">
|
||||
<select data-placeholder="Core Selector"
|
||||
ng-model="currentCore"
|
||||
chosen
|
||||
ng-change="showCore(currentCore)"
|
||||
ng-options="core.name for core in cores"></select>
|
||||
</div>
|
||||
<p id="has-no-cores" ng-show="cores.length==0"><a href="#/~cores">
|
||||
|
@ -167,18 +193,18 @@ limitations under the License.
|
|||
<span>Go and create one</span>
|
||||
</a></p>
|
||||
</div>
|
||||
<div id="core-menu" ng-show="currentCore">
|
||||
<div id="core-menu" class="sub-menu" ng-show="currentCore">
|
||||
<ul>
|
||||
<li class="overview" ng-class="{active:page=='overview'}"><a href="#/{{currentCore.name}}"><span>Overview</span></a></li>
|
||||
<li class="analysis" ng-class="{active:page=='analysis'}"><a href="#/{{currentCore.name}}/analysis"><span>Analysis</span></a></li>
|
||||
<li class="dataimport" ng-class="{active:page=='dataimport'}"><a href="#/{{currentCore.name}}/dataimport"><span>Dataimport</span></a></li>
|
||||
<li class="documents" ng-class="{active:page=='documents'}"><a href="#/{{currentCore.name}}/documents"><span>Documents</span></a></li>
|
||||
<li class="files" ng-class="{active:page=='files'}"><a href="#/{{currentCore.name}}/files"><span>Files</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="analysis" ng-class="{active:page=='analysis'}"><a href="#/{{currentCore.name}}/analysis"><span>Analysis</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="dataimport" ng-class="{active:page=='dataimport'}"><a href="#/{{currentCore.name}}/dataimport"><span>Dataimport</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="documents" ng-class="{active:page=='documents'}"><a href="#/{{currentCore.name}}/documents"><span>Documents</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="files" ng-class="{active:page=='files'}"><a href="#/{{currentCore.name}}/files"><span>Files</span></a></li>
|
||||
<li class="ping" ng-class="{active:page=='ping'}"><a ng-click="ping()"><span>Ping</span><small class="qtime" ng-show="pingMS"> (<span>{{pingMS}}ms</span>)</small></a></li>
|
||||
<li class="plugins" ng-class="{active:page=='plugins'}"><a href="#/{{currentCore.name}}/plugins"><span>Plugins / Stats</span></a></li>
|
||||
<li class="query" ng-class="{active:page=='query'}"><a href="#/{{currentCore.name}}/query"><span>Query</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="query" ng-class="{active:page=='query'}"><a href="#/{{currentCore.name}}/query"><span>Query</span></a></li>
|
||||
<li class="replication" ng-class="{active:page=='replication'}"><a href="#/{{currentCore.name}}/replication"><span>Replication</span></a></li>
|
||||
<li class="schema-browser" ng-class="{active:page=='schema-browser'}"><a href="#/{{currentCore.name}}/schema-browser"><span>Schema Browser</span></a></li>
|
||||
<li ng-hide="isCloudEnabled" class="schema-browser" ng-class="{active:page=='schema-browser'}"><a href="#/{{currentCore.name}}/schema-browser"><span>Schema Browser</span></a></li>
|
||||
<li class="segments" ng-class="{active:page=='segments'}"><a href="#/{{currentCore.name}}/segments"><span>Segments info</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -63,6 +63,10 @@ solrAdminApp.config([
|
|||
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'
|
||||
|
@ -121,6 +125,11 @@ solrAdminApp.config([
|
|||
redirectTo: '/'
|
||||
});
|
||||
}])
|
||||
.constant('Constants', {
|
||||
IS_ROOT_PAGE: 1,
|
||||
IS_CORE_PAGE: 2,
|
||||
IS_COLLECTION_PAGE: 3
|
||||
})
|
||||
.filter('highlight', function($sce) {
|
||||
return function(input, lang) {
|
||||
if (lang && input && lang!="text") return hljs.highlight(lang, input).value;
|
||||
|
@ -319,9 +328,17 @@ solrAdminApp.config([
|
|||
};
|
||||
});
|
||||
|
||||
solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $location, Cores, System, Ping) {
|
||||
solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $location, Cores, Collections, System, Ping, Constants) {
|
||||
|
||||
$rootScope.hideException = function() {delete $rootScope.exception};
|
||||
|
||||
$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;
|
||||
|
@ -329,22 +346,35 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
|
|||
for (key in data.status) {
|
||||
var core = data.status[key];
|
||||
$scope.cores.push(core);
|
||||
if (core.name == currentCoreName) {
|
||||
if ((!$scope.isSolrCloud || pageType == Constants.IS_CORE_PAGE) && core.name == currentCoreName) {
|
||||
$scope.currentCore = core;
|
||||
}
|
||||
}
|
||||
});
|
||||
System.get(function(data) {
|
||||
$scope.isCloudEnabled = data.mode.match( /solrcloud/i )
|
||||
});
|
||||
};
|
||||
$scope.refresh();
|
||||
|
||||
$scope.resetMenu = function(page, isMainPage) {
|
||||
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;
|
||||
if (isMainPage) delete $scope.currentCore;
|
||||
};
|
||||
|
||||
$scope.ping = function() {
|
||||
|
@ -357,8 +387,16 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
|
|||
$scope.dumpCloud = function() {
|
||||
$scope.$broadcast("cloud-dump");
|
||||
}
|
||||
});
|
||||
|
||||
$scope.showCore = function(core) {
|
||||
$location.url("/" + core.name);
|
||||
}
|
||||
|
||||
$scope.showCollection = function(collection) {
|
||||
$location.url("/" + collection.name + "/collection-overview")
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
(function(window, angular, undefined) {
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('AnalysisController',
|
||||
function($scope, $location, $routeParams, Luke, Analysis) {
|
||||
$scope.resetMenu("analysis");
|
||||
function($scope, $location, $routeParams, Luke, Analysis, Constants) {
|
||||
$scope.resetMenu("analysis", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
Luke.schema({core: $routeParams.core}, function(data) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('CloudController',
|
||||
function($scope, $location, Zookeeper) {
|
||||
function($scope, $location, Zookeeper, Constants) {
|
||||
|
||||
$scope.showDebug = false;
|
||||
|
||||
|
@ -30,13 +30,13 @@ solrAdminApp.controller('CloudController',
|
|||
|
||||
var view = $location.search().view ? $location.search().view : "graph";
|
||||
if (view == "tree") {
|
||||
$scope.resetMenu("cloud-tree", true);
|
||||
$scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE);
|
||||
treeSubController($scope, Zookeeper);
|
||||
} else if (view == "rgraph") {
|
||||
$scope.resetMenu("cloud-rgraph", true);
|
||||
$scope.resetMenu("cloud-rgraph", Constants.IS_ROOT_PAGE);
|
||||
graphSubController($scope, Zookeeper, true);
|
||||
} else if (view == "graph") {
|
||||
$scope.resetMenu("cloud-graph", true);
|
||||
$scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE);
|
||||
graphSubController($scope, Zookeeper, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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.showReplica = function(replica) {
|
||||
replica.show = !replica.show;
|
||||
}
|
||||
|
||||
$scope.hideShard = function(shard) {
|
||||
shard.hide = !shard.hide;
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
});
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('CoreOverviewController',
|
||||
function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication, Ping) {
|
||||
$scope.resetMenu("overview");
|
||||
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) {
|
||||
|
|
|
@ -17,30 +17,27 @@
|
|||
|
||||
// @todo test optimize (delete stuff, watch button appear, test button/form)
|
||||
solrAdminApp.controller('CoreAdminController',
|
||||
['$scope', '$routeParams', '$location', '$timeout', 'Cores', 'Update',
|
||||
function($scope, $routeParams, $location, $timeout, Cores, Update){
|
||||
$scope.resetMenu("cores", true);
|
||||
$scope.currentCore = $routeParams.corename; // use 'corename' not 'core' to distinguish from /solr/:core/
|
||||
function($scope, $routeParams, $location, $timeout, 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;
|
||||
for (_obj in data.status) coreCount++;
|
||||
$scope.hasCores = coreCount >0;
|
||||
if (!$scope.currentCore && coreCount==0) {
|
||||
if (!$scope.selectedCore && coreCount==0) {
|
||||
$scope.showAddCore();
|
||||
return;
|
||||
} else if (!$scope.currentCore) {
|
||||
} else if (!$scope.selectedCore) {
|
||||
for (firstCore in data.status) break;
|
||||
$scope.currentCore = firstCore;
|
||||
$location.path("/~cores/" + $scope.currentCore).replace();
|
||||
$scope.selectedCore = firstCore;
|
||||
$location.path("/~cores/" + $scope.selectedCore).replace();
|
||||
}
|
||||
$scope.core = data.status[$scope.currentCore];
|
||||
var cores = [];
|
||||
$scope.core = data.status[$scope.selectedCore];
|
||||
$scope.corelist = [];
|
||||
for (var core in data.status) {
|
||||
cores.push(data.status[core]);
|
||||
$scope.corelist.push(data.status[core]);
|
||||
}
|
||||
$scope.cores = cores;
|
||||
$scope.$parent.refresh();
|
||||
});
|
||||
};
|
||||
$scope.showAddCore = function() {
|
||||
|
@ -87,9 +84,9 @@ solrAdminApp.controller('CoreAdminController',
|
|||
};
|
||||
|
||||
$scope.unloadCore = function() {
|
||||
var answer = confirm( 'Do you really want to unload Core "' + $scope.currentCore + '"?' );
|
||||
var answer = confirm( 'Do you really want to unload Core "' + $scope.selectedCore + '"?' );
|
||||
if( !answer ) return;
|
||||
Cores.unload({core: $scope.currentCore}, function(data) {
|
||||
Cores.unload({core: $scope.selectedCore}, function(data) {
|
||||
$location.path("/~cores");
|
||||
});
|
||||
};
|
||||
|
@ -101,11 +98,11 @@ solrAdminApp.controller('CoreAdminController',
|
|||
|
||||
$scope.renameCore = function() {
|
||||
if (!$scope.other) {
|
||||
$scope.renameMessage = "Please provide a new name for the " + $scope.currentCore + " core";
|
||||
} else if ($scope.other == $scope.currentCore) {
|
||||
$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.currentCore, other: $scope.other}, function(data) {
|
||||
Cores.rename({core:$scope.selectedCore, other: $scope.other}, function(data) {
|
||||
$location.path("/~cores/" + $scope.other);
|
||||
$scope.cancelRename();
|
||||
});
|
||||
|
@ -126,10 +123,10 @@ solrAdminApp.controller('CoreAdminController',
|
|||
$scope.swapCores = function() {
|
||||
if ($scope.swapOther) {
|
||||
$swapMessage = "Please select a core to swap with";
|
||||
} else if ($scope.swapOther == $scope.currentCore) {
|
||||
} else if ($scope.swapOther == $scope.selectedCore) {
|
||||
$swapMessage = "Cannot swap with the same core";
|
||||
} else {
|
||||
Cores.swap({core: $scope.currentCore, other: $scope.swapOther}, function(data) {
|
||||
Cores.swap({core: $scope.selectedCore, other: $scope.swapOther}, function(data) {
|
||||
$location.path("/~cores/" + $scope.swapOther);
|
||||
delete $scope.swapOther;
|
||||
$scope.cancelSwap();
|
||||
|
@ -143,7 +140,7 @@ solrAdminApp.controller('CoreAdminController',
|
|||
}
|
||||
|
||||
$scope.reloadCore = function() {
|
||||
Cores.reload({core: $scope.currentCore},
|
||||
Cores.reload({core: $scope.selectedCore},
|
||||
function(successData) {
|
||||
$scope.reloadSuccess = true;
|
||||
$timeout(function() {$scope.reloadSuccess=false}, 1000);
|
||||
|
@ -151,7 +148,7 @@ solrAdminApp.controller('CoreAdminController',
|
|||
function(failureData) {
|
||||
$scope.reloadFailure = true;
|
||||
$timeout(function() {$scope.reloadFailure=false}, 1000);
|
||||
$scope.currentCore = null;
|
||||
$scope.selectedCore = null;
|
||||
$scope.refresh();
|
||||
$location.path("/~cores");
|
||||
});
|
||||
|
@ -164,7 +161,7 @@ solrAdminApp.controller('CoreAdminController',
|
|||
};
|
||||
|
||||
$scope.optimizeCore = function() {
|
||||
Update.optimize({core: $scope.currentCore},
|
||||
Update.optimize({core: $scope.selectedCore},
|
||||
function(successData) {
|
||||
$scope.optimizeSuccess = true;
|
||||
$timeout(function() {$scope.optimizeSuccess=false}, 1000);
|
||||
|
@ -179,7 +176,7 @@ solrAdminApp.controller('CoreAdminController',
|
|||
|
||||
$scope.refresh();
|
||||
}
|
||||
]);
|
||||
);
|
||||
|
||||
/**************
|
||||
'cores_load_data',
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
var dataimport_timeout = 2000;
|
||||
|
||||
solrAdminApp.controller('DataImportController',
|
||||
function($scope, $rootScope, $routeParams, $location, $timeout, $interval, $cookies, Mbeans, DataImport) {
|
||||
$scope.resetMenu("dataimport");
|
||||
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: 'QUERYHANDLER'}, function (data) {
|
||||
|
|
|
@ -24,8 +24,8 @@ var DOC_PLACEHOLDER = '<doc>\n' +
|
|||
var ADD_PLACEHOLDER = '<add>\n' + DOC_PLACEHOLDER + '</add>\n';
|
||||
|
||||
solrAdminApp.controller('DocumentsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Luke, Update, FileUpload) {
|
||||
$scope.resetMenu("documents");
|
||||
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) {
|
||||
|
|
|
@ -19,8 +19,8 @@ var contentTypeMap = { xml : 'text/xml', html : 'text/html', js : 'text/javascri
|
|||
var languages = {js: "javascript", xml:"xml", xsl:"xml", vm: "xml", html: "xml", json: "text", css: "css"};
|
||||
|
||||
solrAdminApp.controller('FilesController',
|
||||
function($scope, $rootScope, $routeParams, $location, Files) {
|
||||
$scope.resetMenu("files");
|
||||
function($scope, $rootScope, $routeParams, $location, Files, Constants) {
|
||||
$scope.resetMenu("files", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.file = $location.search().file;
|
||||
$scope.content = null;
|
||||
|
|
|
@ -15,8 +15,8 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('IndexController', ['$scope', 'System', 'Cores', function($scope, System, Cores) {
|
||||
$scope.resetMenu("index", true);
|
||||
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;
|
||||
|
@ -67,7 +67,7 @@ solrAdminApp.controller('IndexController', ['$scope', 'System', 'Cores', functio
|
|||
});
|
||||
};
|
||||
$scope.reload();
|
||||
}]);
|
||||
});
|
||||
|
||||
var parse_memory_value = function( value ) {
|
||||
if( value !== Number( value ) )
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('JavaPropertiesController',
|
||||
function($scope, Properties){
|
||||
$scope.resetMenu("java-props", true);
|
||||
function($scope, Properties, Constants){
|
||||
$scope.resetMenu("java-props", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Properties.get(function(data) {
|
||||
var sysprops = data["system.properties"];
|
||||
|
|
|
@ -24,8 +24,8 @@ var format_time_content = function( time, timeZone ) {
|
|||
}
|
||||
|
||||
solrAdminApp.controller('LoggingController',
|
||||
function($scope, $timeout, $cookies, Logging){
|
||||
$scope.resetMenu("logging", true);
|
||||
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) {
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('PluginsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Mbeans) {
|
||||
$scope.resetMenu("plugins");
|
||||
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
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('QueryController',
|
||||
function($scope, $routeParams, $location, Query){
|
||||
$scope.resetMenu("query");
|
||||
function($scope, $routeParams, $location, Query, Constants){
|
||||
$scope.resetMenu("query", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
// @todo read URL parameters into scope
|
||||
$scope.query = {wt: 'json', q:'*:*', indent:'on'};
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('ReplicationController',
|
||||
function($scope, $rootScope, $routeParams, $interval, $timeout, Replication) {
|
||||
$scope.resetMenu("replication");
|
||||
function($scope, $rootScope, $routeParams, $interval, $timeout, Replication, Constants) {
|
||||
$scope.resetMenu("replication", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.iterationCount = 1;
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
var cookie_schema_browser_autoload = 'schema-browser_autoload';
|
||||
|
||||
solrAdminApp.controller('SchemaBrowserController',
|
||||
function($scope, $routeParams, $location, $cookies, Luke) {
|
||||
$scope.resetMenu("schema-browser");
|
||||
function($scope, $routeParams, $location, $cookies, Luke, Constants) {
|
||||
$scope.resetMenu("schema-browser", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Luke.schema({core: $routeParams.core}, function (schema) {
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
var MB_FACTOR = 1024*1024;
|
||||
|
||||
solrAdminApp.controller('SegmentsController', function($scope, $routeParams, $interval, Segments) {
|
||||
$scope.resetMenu("segments");
|
||||
solrAdminApp.controller('SegmentsController', function($scope, $routeParams, $interval, Segments, Constants) {
|
||||
$scope.resetMenu("segments", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
*/
|
||||
|
||||
solrAdminApp.controller('ThreadsController',
|
||||
["$scope", "Threads",
|
||||
function($scope, Threads){
|
||||
$scope.resetMenu("threads", true);
|
||||
function($scope, Threads, Constants){
|
||||
$scope.resetMenu("threads", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Threads.get(function(data) {
|
||||
var threadDump = data.system.threadDump;
|
||||
|
@ -48,4 +47,4 @@ solrAdminApp.controller('ThreadsController',
|
|||
}
|
||||
};
|
||||
$scope.refresh();
|
||||
}]);
|
||||
});
|
||||
|
|
|
@ -35,6 +35,15 @@ solrAdminServices.factory('System',
|
|||
"optimize": {params:{}}
|
||||
});
|
||||
}])
|
||||
.factory('Collections',
|
||||
['$resource', function($resource) {
|
||||
return $resource('/solr/admin/collections',
|
||||
{wt: 'json', _:Date.now()}, {
|
||||
"list": {params:{action: "LIST"}},
|
||||
"status": {params:{action: "CLUSTERSTATUS"}}
|
||||
}
|
||||
)
|
||||
}])
|
||||
.factory('Logging',
|
||||
['$resource', function($resource) {
|
||||
return $resource('/solr/admin/info/logging', {'wt':'json', '_':Date.now()}, {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<!--
|
||||
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="dashboard">
|
||||
|
||||
<div class="clearfix">
|
||||
|
||||
<div id="collection" class="block fieldlist">
|
||||
|
||||
<h2><span>Collection: {{selectedCollection.name}}</span></h2>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<dl>
|
||||
|
||||
<dt>Config name:</dt>
|
||||
<dd class="value">{{selectedCollection.configName}}</dd>
|
||||
|
||||
<dt>Max shards per node:</dt>
|
||||
<dd class="value">{{selectedCollection.maxShardsPerNode}}</dd>
|
||||
|
||||
<dt>Replication factor:</dt>
|
||||
<dd class="value">{{selectedCollection.replicationFactor}}</dd>
|
||||
|
||||
<dt>Auto-add replicas:</dt>
|
||||
<dd class="ico value" ng-class="selectedCollection.autoAddReplicas ? 'ico-1' : 'ico-0'"><span>yes</span></dd>
|
||||
|
||||
<dt>Router name:</dt>
|
||||
<dd class="value">{{selectedCollection.router.name}}</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="shards" class="block fieldlist">
|
||||
|
||||
<h2><span>Shards</span></h2>
|
||||
|
||||
<div>
|
||||
|
||||
<div class="shard" ng-repeat="(name, shard) in selectedCollection.shards">
|
||||
<a ng-click="hideShard(shard)"><h3 class="shard-title">{{name}}</h3></a>
|
||||
<dl class="shard-detail clearfix" ng-hide="shard.hide">
|
||||
<dt>Range:</dt>
|
||||
<dd class="value">{{ shard.range }}</dd>
|
||||
|
||||
<dt>Active:</dt>
|
||||
<dd class="ico value" ng-class="shard.state='active' ? 'ico-1' : 'ico-0'"><span>yes</span></dd>
|
||||
|
||||
<dt>Replicas:</dt>
|
||||
<dd>
|
||||
<div class="replica clearfix {{$odd?'odd':''}}" ng-repeat="(name, replica) in shard.replicas">
|
||||
<a ng-click="showReplica(replica)"><h3>{{replica.core}}</h3></a>
|
||||
<dl ng-show="replica.show">
|
||||
<dt>Base URL: </dt><dd>{{replica.base_url}}</dd>
|
||||
<dt>Core: </dt><dd><a href="{{replica.base_url}}/{{replica.core}}">{{replica.core}}</a></dd>
|
||||
<dt>Leader: </dt>
|
||||
<dd class="ico value" ng-class="selectedCollection.autoAddReplicas ? 'ico-1' : 'ico-0'"><span>yes</span></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -106,10 +106,10 @@ limitations under the License.
|
|||
<form>
|
||||
|
||||
<p class="clearfix"><label for="swap_core">this:</label>
|
||||
<input type="text" id="swap_core" name="core" ng-model="currentCore" readonly="readonly"></p>
|
||||
<input type="text" id="swap_core" name="core" ng-model="selectedCore" readonly="readonly"></p>
|
||||
|
||||
<p class="clearfix"><label for="swap_other">and:</label>
|
||||
<select name="other" ng-model="swapOther" ng-options="core.name as core.name for core in cores" class="other">
|
||||
<select name="other" ng-model="swapOther" ng-options="core.name as core.name for core in corelist" class="other">
|
||||
</select></p>
|
||||
|
||||
<p class="clearfix note error" ng-show="swapMessage">
|
||||
|
|
|
@ -112,6 +112,8 @@ limitations under the License.
|
|||
<div class="trigger">
|
||||
|
||||
<button class="submit" ng-click="toggleTerms()"><span ng-class="{loader:isLoadingTerms}">Load Term Info</span></button>
|
||||
<br/>
|
||||
<span ng-show="isCloudEnabled">N.B. Loaded from a single core - not from the whole collection.</span>
|
||||
|
||||
<a ng-show="showTerms" ng-click="toggleAutoload()" ng-class="{on:isAutoload}" class="autoload" title="Automatically load Term Info?"><span>Autoload</span></a>
|
||||
|
||||
|
|
Loading…
Reference in New Issue