SOLR-13122: Ability to query aliases in Solr Admin UI

This commit is contained in:
Jan Høydahl 2019-08-30 14:16:58 +02:00
parent 6dea678439
commit 52be32d4ad
11 changed files with 365 additions and 151 deletions

View File

@ -126,6 +126,7 @@ New Features
* SOLR-13710: Persist package jars locally & expose them over http at /api/node/blob (noble)
* SOLR-13122: Ability to query aliases in Solr Admin UI (janhoy)
Improvements
----------------------
@ -147,7 +148,7 @@ Improvements
* SOLR-13542: Code cleanup - Avoid using stream filter count where possible (Koen De Groote via Tomás Fernández Löbbe)
* SOLR-13720: BlockJoinParentQParser.getCachedFilter()made public for accessing from QParser plugins
(Stanislav Livotov via Mikhail Khludnev)
(Stanislav Livotov via Mikhail Khludnev)
Bug Fixes
----------------------

View File

@ -40,7 +40,6 @@ limitations under the License.
#content #collections #navigation
{
padding-top: 50px;
width: 12%;
}
@ -49,6 +48,17 @@ limitations under the License.
padding-left: 5px;
}
#content #collections #navigation ul
{
padding-top: 20px;
}
#content #collections #navigation hr
{
margin-top: 20px;
margin-bottom: 20px;
}
#content #collections #frame .actions
{
margin-bottom: 20px;
@ -129,23 +139,24 @@ limitations under the License.
background-image: url( ../../img/ico/cross.png );
}
#content #collections .actions #add
{
left: 0;
position: absolute;
}
#content #collections .actions #add span
#content #collections #navigation #add span
{
background-image: url( ../../img/ico/plus-button.png );
}
#content #collections .actions #delete
#content #collections #navigation #create-alias span
{
background-image: url( ../../img/ico/arrow-switch.png );
}
#content #collections .actions #delete-collection,
#content #collections .actions #delete-alias
{
margin-right: 20px;
}
#content #collections .actions #delete span
#content #collections .actions #delete-collection span
{
background-image: url( ../../img/ico/cross.png );
}
@ -160,11 +171,6 @@ limitations under the License.
background-image: url( ../../img/ico/ui-text-field-select.png );
}
#content #collections .actions #create-alias span
{
background-image: url( ../../img/ico/arrow-switch.png );
}
#content #collections .actions #delete-alias span
{
background-image: url( ../../img/ico/cross-button.png );
@ -215,6 +221,7 @@ limitations under the License.
background-position: 0% 50%;
}
#content #collections #data #alias-data h2 { background-image: url( ../../img/ico/box.png ); }
#content #collections #data #collection-data h2 { background-image: url( ../../img/ico/box.png ); }
#content #collections #data #shard-data h2 { background-image: url( ../../img/ico/sitemap.png ); }
#content #collections #data #shard-data .replica h2 { background-image: url( ../../img/ico/node-slave.png ); }
@ -355,6 +362,11 @@ limitations under the License.
width: 100% !important;
}
#content #collections #alias-data {
float: left;
width: 35%;
}
#content #collections #collection-data {
float: left;
width: 35%;

View File

@ -0,0 +1,42 @@
/*
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 .collprops
{
float: left;
}
#content #dashboard .collprops dt,
#content #dashboard .collprops dd
{
display: block;
float: left;
}
#content #dashboard .collprops dt
{
clear: left;
margin-right: 2%;
width: 48%;
}
#content #dashboard .collprops dd
{
width: 50%;
}

View File

@ -46,6 +46,7 @@ limitations under the License.
<link rel="stylesheet" type="text/css" href="css/angular/segments.css?_=${version}">
<link rel="stylesheet" type="text/css" href="css/angular/threads.css?_=${version}">
<link rel="stylesheet" type="text/css" href="css/angular/chosen.css?_=${version}">
<link rel="stylesheet" type="text/css" href="css/angular/overview.css?_=${version}">
<link rel="stylesheet" type="text/css" href="css/angular/jquery-ui.min.css?_=${version}">
<link rel="stylesheet" type="text/css" href="css/angular/jquery-ui.structure.min.css?_=${version}">
@ -73,6 +74,7 @@ limitations under the License.
<script src="js/angular/controllers/cores.js"></script>
<script src="js/angular/controllers/threads.js"></script>
<script src="js/angular/controllers/java-properties.js"></script>
<script src="js/angular/controllers/alias-overview.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>
@ -180,7 +182,7 @@ limitations under the License.
ng-model="currentCollection"
chosen
ng-change="showCollection(currentCollection)"
ng-options="collection.name for collection in collections"></select>
ng-options="collection.name for collection in aliases_and_collections"></select>
</div>
<p id="has-no-collections" ng-show="collections.length==0"><a href="#/~collections">
No collections available
@ -189,14 +191,15 @@ limitations under the License.
</div>
<div id="collection-menu" class="sub-menu" ng-show="currentCollection">
<ul>
<li class="overview" ng-class="{active:page=='collection-overview'}"><a href="#/{{currentCollection.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="overview" ng-show="currentCollection.type === 'collection'" ng-class="{active:page=='collection-overview'}"><a href="#/{{currentCollection.name}}/collection-overview"><span>Overview</span></a></li>
<li class="overview" ng-show="currentCollection.type === 'alias'" ng-class="{active:page=='alias-overview'}"><a href="#/{{currentCollection.name}}/alias-overview"><span>Overview</span></a></li>
<li class="analysis" ng-show="!isMultiDestAlias(currentCollection)" ng-class="{active:page=='analysis'}"><a href="#/{{currentCollection.name}}/analysis"><span>Analysis</span></a></li>
<li class="dataimport" ng-show="!isMultiDestAlias(currentCollection)" ng-class="{active:page=='dataimport'}"><a href="#/{{currentCollection.name}}/dataimport"><span>Dataimport</span></a></li>
<li class="documents" ng-show="!isMultiDestAlias(currentCollection)" ng-class="{active:page=='documents'}"><a href="#/{{currentCollection.name}}/documents"><span>Documents</span></a></li>
<li class="files" ng-show="!isMultiDestAlias(currentCollection)" 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="stream" ng-class="{active:page=='stream'}"><a href="#/{{currentCollection.name}}/stream"><span>Stream</span></a></li>
<li class="schema" ng-class="{active:page=='schema'}"><a href="#/{{currentCollection.name}}/schema"><span>Schema</span></a></li>
<li class="schema" ng-show="!isMultiDestAlias(currentCollection)" ng-class="{active:page=='schema'}"><a href="#/{{currentCollection.name}}/schema"><span>Schema</span></a></li>
</ul>
</div>
<div id="core-selector">

View File

@ -88,6 +88,10 @@ solrAdminApp.config([
templateUrl: 'partials/core_overview.html',
controller: 'CoreOverviewController'
}).
when('/:core/alias-overview', {
templateUrl: 'partials/alias_overview.html',
controller: 'AliasOverviewController'
}).
when('/:core/collection-overview', {
templateUrl: 'partials/collection_overview.html',
controller: 'CollectionOverviewController'
@ -444,6 +448,7 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
$scope.refresh = function() {
$scope.cores = [];
$scope.collections = [];
$scope.aliases = [];
}
$scope.refresh();
@ -466,19 +471,39 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
System.get(function(data) {
$scope.isCloudEnabled = data.mode.match( /solrcloud/i );
var currentCollectionName = $route.current.params.core;
delete $scope.currentCollection;
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;
Collections.list(function (cdata) {
Collections.listaliases(function (adata) {
$scope.aliases = [];
for (var key in adata.aliases) {
props = {};
if (key in adata.properties) {
props = adata.properties[key];
}
var alias = {name: key, collections: adata.aliases[key], type: 'alias', properties: props};
$scope.aliases.push(alias);
if (pageType == Constants.IS_COLLECTION_PAGE && alias.name == currentCollectionName) {
$scope.currentCollection = alias;
}
}
}
})
$scope.collections = [];
for (key in cdata.collections) {
var collection = {name: cdata.collections[key], type: 'collection'};
$scope.collections.push(collection);
if (pageType == Constants.IS_COLLECTION_PAGE && collection.name == currentCollectionName) {
$scope.currentCollection = collection;
}
}
$scope.aliases_and_collections = $scope.aliases;
if ($scope.aliases.length > 0) {
$scope.aliases_and_collections = $scope.aliases_and_collections.concat({name:'-----'});
}
$scope.aliases_and_collections = $scope.aliases_and_collections.concat($scope.collections);
});
});
}
$scope.showEnvironment = data.environment !== undefined;
@ -502,6 +527,10 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
$scope.http401 = sessionStorage.getItem("http401");
};
$scope.isMultiDestAlias = function(selectedColl) {
return selectedColl && selectedColl.type === 'alias' && selectedColl.collections.includes(',');
};
$scope.ping = function() {
Ping.ping({core: $scope.currentCore.name}, function(data) {
$scope.showPing = true;
@ -519,8 +548,12 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $
}
$scope.showCollection = function(collection) {
$location.url("/" + collection.name + "/collection-overview")
}
if (collection.type === 'collection') {
$location.url("/" + collection.name + "/collection-overview")
} else if (collection.type === 'alias') {
$location.url("/" + collection.name + "/alias-overview")
}
};
$scope.$on('$routeChangeStart', function() {
$rootScope.exceptions = {};

View File

@ -0,0 +1,27 @@
/*
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('AliasOverviewController',
function($scope, $routeParams, Collections, Constants) {
$scope.resetMenu("collection-overview", Constants.IS_COLLECTION_PAGE);
$scope.refresh = function() {
$scope.selectedCollection = $scope.currentCollection;
};
$scope.refresh();
});

View File

@ -28,6 +28,7 @@ solrAdminApp.controller('CollectionsController',
for (var name in data.cluster.collections) {
var collection = data.cluster.collections[name];
collection.name = name;
collection.type = 'collection';
var shards = collection.shards;
collection.shards = [];
for (var shardName in shards) {
@ -50,10 +51,28 @@ solrAdminApp.controller('CollectionsController',
$scope.collection = collection;
}
}
if ($routeParams.collection && !$scope.collection) {
alert("No collection called " + $routeParams.collection)
$location.path("/~collections");
}
// Fetch aliases using LISTALIASES to get properties
Collections.listaliases(function (adata) {
// TODO: Population of aliases array duplicated in app.js
$scope.aliases = [];
for (var key in adata.aliases) {
props = {};
if (key in adata.properties) {
props = adata.properties[key];
}
var alias = {name: key, collections: adata.aliases[key], type: 'alias', properties: props};
$scope.aliases.push(alias);
if ($routeParams.collection == 'alias_' + key) {
$scope.collection = alias;
}
}
// Decide what is selected in list
if ($routeParams.collection && !$scope.collection) {
alert("No collection or alias called " + $routeParams.collection);
$location.path("/~collections");
}
});
$scope.liveNodes = data.cluster.liveNodes;
});
Zookeeper.configs(function(data) {
@ -96,14 +115,6 @@ solrAdminApp.controller('CollectionsController',
$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() {
@ -116,12 +127,16 @@ solrAdminApp.controller('CollectionsController',
collections.push($scope.aliasCollections[i].name);
}
Collections.createAlias({name: $scope.aliasToCreate, collections: collections.join(",")}, function(data) {
$scope.hideAll();
$scope.cancelCreateAlias();
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
$location.path("/~collections/alias_" + $scope.aliasToCreate);
});
}
$scope.deleteAlias = function() {
Collections.deleteAlias({name: $scope.aliasToDelete}, function(data) {
Collections.deleteAlias({name: $scope.collection.name}, function(data) {
$scope.hideAll();
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
$location.path("/~collections/");
});
};

View File

@ -30,6 +30,7 @@ solrAdminServices.factory('System',
return $resource('admin/collections',
{'wt':'json', '_':Date.now()}, {
"list": {params:{action: "LIST"}},
"listaliases": {params:{action: "LISTALIASES"}},
"status": {params:{action: "CLUSTERSTATUS"}},
"add": {params:{action: "CREATE"}},
"delete": {params:{action: "DELETE"}},
@ -140,6 +141,11 @@ solrAdminServices.factory('System',
}).success(success).error(error);
}
})
.filter('splitByComma', function() {
return function(input) {
return input === undefined ? input : input.split(',');
}
})
.factory('Luke',
['$resource', function($resource) {
return $resource(':core/admin/luke', {core: '@core', wt:'json', _:Date.now()}, {

View File

@ -0,0 +1,46 @@
<!--
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 collprops">
<h2><span>Alias: {{selectedCollection.name}}</span></h2>
<div class="content">
<dl>
<dt><span>Collections:</span></dt>
<dd>
<span ng-repeat="coll in (selectedCollection.collections | splitByComma)">
<a href="#~collections/{{coll}}">{{coll}}</a>{{$last ? '' : ', '}}
</span>
</dd>
<span ng-repeat="(key, value) in selectedCollection.properties">
<dt><span>{{ key }}</span></dt>
<dd>{{ value }}</dd>
</span>
</dl>
</div>
</div>
</div>
</div>

View File

@ -18,7 +18,7 @@ limitations under the License.
<div class="clearfix">
<div id="collection" class="block fieldlist">
<div id="collection" class="block collprops">
<h2><span>Collection: {{selectedCollection.name}}</span></h2>

View File

@ -18,77 +18,101 @@ limitations under the License.
<div id="ui-block" style="display:none">&nbsp;</div><!-- @todo what is this for? -->
<div id="frame">
<div class="actions clearfix">
<div class="action add" data-rel="add" ng-show="showAdd" style="left:0px">
<div id="actions" class="actions clearfix">
<form>
<button id="add" class="action" ng-click="showAddCollection()"><span>Add Collection</span></button>
<button id="delete" class="warn requires-core" ng-click="showDeleteCollection()" ng-show="collection"><span>Delete</span></button>
<button id="reload" class="requires-core" ng-click="reloadCollection()" ng-show="collection"
ng-class="{success: reloadSuccess, warn: reloadFailure}"><span>Reload</span></button>
<button id="create-alias" class="action requires-core" ng-click="toggleCreateAlias()"><span>Create Alias</span></button>
<button id="delete-alias" class="action requires-core" ng-click="toggleDeleteAlias()"><span>Delete Alias</span></button>
<div class="action add" data-rel="add" ng-show="showAdd" style="left:0px">
<form>
<p class="clearfix"><label for="add_name">name:</label>
<p class="clearfix"><label for="add_name">name:</label>
<input type="text" name="name" id="add_name" ng-model="newCollection.name" placeholder="new collection"></p>
<p class="clearfix"><label for="add_config">config set:</label>&nbsp;
<p class="clearfix"><label for="add_config">config set:</label>&nbsp;
<select chosen ng-options="config.name as config.name for config in configs" name="config_name" id="add_config" ng-model="newCollection.configName">
</select>
</p>
</p>
<p class="clearfix"><label for="add_numShards">numShards:</label>
<p class="clearfix"><label for="add_numShards">numShards:</label>
<input type="text" name="numShards" id="add_numShards" ng-model="newCollection.numShards"></p>
<p class="clearfix"><label for="add_replicationFactor">replicationFactor:</label>
<p class="clearfix"><label for="add_replicationFactor">replicationFactor:</label>
<input type="text" name="replicationFactor" id="add_replicationFactor" ng-model="newCollection.replicationFactor"></p>
<p class="clearfix"><a ng-click="showAdvanced=!showAdvanced">
<span id="add_advanced" ng-class="{open: showAdvanced}">Show advanced</span></a></p>
<div ng-show="showAdvanced">
<p class="clearfix"><a ng-click="showAdvanced=!showAdvanced">
<span id="add_advanced" ng-class="{open: showAdvanced}">Show advanced</span></a></p>
<div ng-show="showAdvanced">
<p>Advanced options: </p>
<p class="clearfix"><label for="add_router_name">router:</label>
<select name="routerName" id="add_router_name" ng-model="newCollection.routerName">
<option value="compositeId">Composite ID</option>
<option value="implicit">Implicit</option>
</select>
</p>
<p class="clearfix"><label for="add_maxShardsPerNode">maxShardsPerNode:</label>
<input type="text" name="replicationFactor" id="add_maxShardsPerNode" ng-model="newCollection.maxShardsPerNode"></p>
<p class="clearfix"><label for="add_shards">shards:</label>
<input type="text" name="shards" id="add_shards" ng-model="newCollection.shards"></p>
<p class="clearfix"><label for="add_routerField">router.field:</label>
<input type="text" name="routerField" id="add_routerField" ng-model="newCollection.routerField"></p>
<p class="clearfix"><label for="add_autoAddReplicas">autoAddReplicas:</label>
<select name="autoAddReplicas" id="add_autoAddReplicas" ng-model="newCollection.autoAddReplicas">
<option value="true">true</option>
<option value="false">false</option>
</select>
</p>
</div>
<p class="clearfix note error" ng-show="addMessage">
<span>{{addMessage}}</span>
<p>Advanced options: </p>
<p class="clearfix"><label for="add_router_name">router:</label>
<select name="routerName" id="add_router_name" ng-model="newCollection.routerName">
<option value="compositeId">Composite ID</option>
<option value="implicit">Implicit</option>
</select>
</p>
<p class="clearfix buttons">
<button type="submit" class="submit" ng-click="addCollection()"><span>Add Collection</span></button>
<button type="reset" class="reset" ng-click="cancelAddCollection()"><span>Cancel</span></button>
<p class="clearfix"><label for="add_maxShardsPerNode">maxShardsPerNode:</label>
<input type="text" name="replicationFactor" id="add_maxShardsPerNode" ng-model="newCollection.maxShardsPerNode"></p>
<p class="clearfix"><label for="add_shards">shards:</label>
<input type="text" name="shards" id="add_shards" ng-model="newCollection.shards"></p>
<p class="clearfix"><label for="add_routerField">router.field:</label>
<input type="text" name="routerField" id="add_routerField" ng-model="newCollection.routerField"></p>
<p class="clearfix"><label for="add_autoAddReplicas">autoAddReplicas:</label>
<select name="autoAddReplicas" id="add_autoAddReplicas" ng-model="newCollection.autoAddReplicas">
<option value="true">true</option>
<option value="false">false</option>
</select>
</p>
</form>
</div>
<p class="clearfix note error" ng-show="addMessage">
<span>{{addMessage}}</span>
</p>
</div>
<p class="clearfix buttons">
<button type="submit" class="submit" ng-click="addCollection()"><span>Add Collection</span></button>
<button type="reset" class="reset" ng-click="cancelAddCollection()"><span>Cancel</span></button>
</p>
</form>
</div>
<div class="action create-alias" ng-show="showCreateAlias">
<form>
<input type="hidden" name="core" data-core="current">
<p class="clearfix"><label for="alias">Alias Name:</label>
<input type="text" name="alias" ng-model="aliasToCreate" id="alias"></p>
<p class="clearfix"><label for="aliasCollections">Collections:</label>
<select multiple id="aliasCollections" ng-model="aliasCollections" ng-options="collection.name for collection in collections" class="other">
</select></p>
<p class="clearfix note error" ng-show="renameMessage">
<span>{{renameMessage}}</span>
</p>
<p class="clearfix buttons">
<button class="submit" ng-click="createAlias()"><span>Create Alias</span></button>
<button type="reset" class="reset" ng-click="cancelCreateAlias()"><span>Cancel</span></button>
</p>
</form>
</div>
</div>
<div id="frame">
<div id="actions" class="actions clearfix" ng-show="collection">
<button id="delete-collection" class="warn requires-core" ng-click="showDeleteCollection()" ng-show="collection && collection.type === 'collection'"><span>Delete collection</span></button>
<button id="delete-alias" class="action requires-core" ng-click="toggleDeleteAlias()" ng-show="collection && collection.type === 'alias'"><span>Delete alias</span></button>
<button id="reload" class="requires-core" ng-click="reloadCollection()" ng-show="collection && collection.type === 'collection'"
ng-class="{success: reloadSuccess, warn: reloadFailure}"><span>Reload</span></button>
<div class="action delete" ng-show="showDelete">
@ -110,56 +134,15 @@ limitations under the License.
</div>
<div class="action create-alias" ng-show="showCreateAlias">
<form>
<input type="hidden" name="core" data-core="current">
<p class="clearfix"><label for="alias">Alias Name:</label>
<input type="text" name="alias" ng-model="aliasToCreate" id="alias"></p>
<p class="clearfix"><label for="aliasCollections">Collections:</label>
<select multiple id="aliasCollections" ng-model="aliasCollections" ng-options="collection.name for collection in collections" class="other">
</select></p>
<p class="clearfix note error" ng-show="renameMessage">
<span>{{renameMessage}}</span>
</p>
<p class="clearfix buttons">
<button class="submit" ng-click="createAlias()"><span>Create Alias</span></button>
<button type="reset" class="reset" ng-click="cancelCreateAlias()"><span>Cancel</span></button>
</p>
</form>
</div>
<div class="action delete-alias" ng-show="showDeleteAlias">
<form>
<span ng-show="aliases">
<p class="clearfix"><label for="deleteAlias">Alias:</label>
<select id="deleteAlias" ng-model="aliasToDelete" ng-options="alias as alias for (alias, collections) in aliases" class="other">
</select></p>
<p class="clearfix note error" ng-show="swapMessage">
<span>{{swapMessage}}</span>
</p>
<p>Are you sure you want to delete alias {{ collection.name }}?</p>
<p class="clearfix buttons">
<button type="submit" class="submit" ng-click="deleteAlias()"><span>Delete Alias</span></button>
<button type="reset" class="reset" ng-click="cancelDeleteAlias()"><span>Cancel</span></button>
</p>
</span>
<span ng-hide="aliases">
<p>No aliases to delete.</p>
<p class="clearfix buttons">
<button type="reset" class="reset" ng-click="cancelDeleteAlias()"><span>Cancel</span></button>
</p>
</span>
</form>
</div>
@ -168,12 +151,42 @@ limitations under the License.
<div class="requires-core" ng-hide="collection">
<h2>Please select a collection</h2>
<h2 ng-show="aliases.length + collections.length > 0">Please select a collection or alias</h2>
</div>
<div id="data" class="requires-core clearfix" ng-show="collection">
<div class="block" id="collection-data">
<div class="block" id="alias-data" ng-show="collection.type === 'alias'">
<h2>Alias: {{collection.name}}</h2>
<div class="message-container">
<div class="message"></div>
</div>
<div class="content">
<ul>
<li>
<dl class="clearfix">
<dt><span>Collections:</span></dt>
<dd>
<span ng-repeat="coll in (collection.collections | splitByComma)">
<a href="#~collections/{{coll}}">{{coll}}</a>{{$last ? '' : ', '}}
</span>
</dd>
<div ng-repeat="(key, value) in collection.properties">
<dt><span>{{ key }}</span></dt>
<dd><span>{{ value }}</span></dd>
</div>
</dl>
</li>
</ul>
</div>
</div>
<div class="block" id="collection-data" ng-show="collection.type === 'collection'">
<h2>Collection: {{collection.name}}</h2>
@ -215,12 +228,21 @@ limitations under the License.
<dt><span>autoAddReplicas:</span></dt>
<dd>{{collection.autoAddReplicas}}</dd>
</dl></li>
<li ng-show="collection.aliases"><dl class="clearfix">
<dt><span>aliases:</span></dt>
<dd>
<span ng-repeat="coll in collection.aliases">
<a href="#~collections/alias_{{coll}}">{{coll}}</a>{{$last ? '' : ', '}}
</span>
</dd>
</dl></li>
</ul>
</div>
</div>
<div class="block" id="shard-data">
<div class="block" id="shard-data" ng-show="collection.type === 'collection'">
<div class="content shard" ng-repeat="shard in collection.shards">
<a ng-click="toggleShard(shard)">
<h2>
@ -358,9 +380,16 @@ limitations under the License.
</div>
<div id="navigation" class="requires-core clearfix">
<button id="add" class="action" ng-click="showAddCollection()"><span>Add Collection</span></button>
<ul>
<li ng-repeat="c in collections" ng-class="{current: collection.name == c.name}"><a href="#~collections/{{c.name}}">{{c.name}}</a></li>
<li ng-repeat="c in collections" ng-class="{current: collection.name == c.name && collection.type === 'collection'}"><a href="#~collections/{{c.name}}">{{c.name}}</a></li>
</ul>
<hr/>
<button id="create-alias" class="action requires-core" ng-click="toggleCreateAlias()" ng-disabled="collections.length == 0"><span>Create Alias</span></button>
<ul>
<li ng-repeat="c in aliases" ng-class="{current: collection.name == c.name && collection.type === 'alias'}"><a href="#~collections/alias_{{c.name}}">{{c.name}}</a></li>
</ul>
</div>
</div>