From e8c2b6af2abfe86196e15ebefc25337bb8536b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 30 Aug 2019 14:16:58 +0200 Subject: [PATCH] SOLR-13122: Ability to query aliases in Solr Admin UI (cherry picked from commit 52be32d4addbead8536dbde84ed8c80af4993b8b) --- solr/CHANGES.txt | 3 +- solr/webapp/web/css/angular/collections.css | 42 ++-- solr/webapp/web/css/angular/overview.css | 42 ++++ solr/webapp/web/index.html | 17 +- solr/webapp/web/js/angular/app.js | 59 ++++- .../js/angular/controllers/alias-overview.js | 27 +++ .../web/js/angular/controllers/collections.js | 43 ++-- solr/webapp/web/js/angular/services.js | 6 + solr/webapp/web/partials/alias_overview.html | 46 ++++ .../web/partials/collection_overview.html | 2 +- solr/webapp/web/partials/collections.html | 229 ++++++++++-------- 11 files changed, 365 insertions(+), 151 deletions(-) create mode 100644 solr/webapp/web/css/angular/overview.css create mode 100644 solr/webapp/web/js/angular/controllers/alias-overview.js create mode 100644 solr/webapp/web/partials/alias_overview.html diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index cd757260515..2f3dae4599a 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -69,6 +69,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 ---------------------- @@ -90,7 +91,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 ---------------------- diff --git a/solr/webapp/web/css/angular/collections.css b/solr/webapp/web/css/angular/collections.css index e8d1207e161..a4eccbe0e9c 100644 --- a/solr/webapp/web/css/angular/collections.css +++ b/solr/webapp/web/css/angular/collections.css @@ -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%; diff --git a/solr/webapp/web/css/angular/overview.css b/solr/webapp/web/css/angular/overview.css new file mode 100644 index 00000000000..4934f7288a5 --- /dev/null +++ b/solr/webapp/web/css/angular/overview.css @@ -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%; +} diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index f1e6a2e8fe9..676ad19ea01 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -46,6 +46,7 @@ limitations under the License. + @@ -73,6 +74,7 @@ limitations under the License. + @@ -180,7 +182,7 @@ limitations under the License. ng-model="currentCollection" chosen ng-change="showCollection(currentCollection)" - ng-options="collection.name for collection in collections"> + ng-options="collection.name for collection in aliases_and_collections">

No collections available @@ -189,14 +191,15 @@ limitations under the License.

diff --git a/solr/webapp/web/js/angular/app.js b/solr/webapp/web/js/angular/app.js index 6ba0d4ca6f2..784ea6e4131 100644 --- a/solr/webapp/web/js/angular/app.js +++ b/solr/webapp/web/js/angular/app.js @@ -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 = {}; diff --git a/solr/webapp/web/js/angular/controllers/alias-overview.js b/solr/webapp/web/js/angular/controllers/alias-overview.js new file mode 100644 index 00000000000..6fbca386fe2 --- /dev/null +++ b/solr/webapp/web/js/angular/controllers/alias-overview.js @@ -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(); +}); diff --git a/solr/webapp/web/js/angular/controllers/collections.js b/solr/webapp/web/js/angular/controllers/collections.js index 111d7ea5602..978fc71e6f1 100644 --- a/solr/webapp/web/js/angular/controllers/collections.js +++ b/solr/webapp/web/js/angular/controllers/collections.js @@ -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/"); }); }; diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 36556399cd2..8b371b6fff3 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -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()}, { diff --git a/solr/webapp/web/partials/alias_overview.html b/solr/webapp/web/partials/alias_overview.html new file mode 100644 index 00000000000..0cf8124b531 --- /dev/null +++ b/solr/webapp/web/partials/alias_overview.html @@ -0,0 +1,46 @@ + +
+ +
+ +
+ +

Alias: {{selectedCollection.name}}

+ +
+ +
+ +
Collections:
+
+ + {{coll}}{{$last ? '' : ', '}} + +
+ + +
{{ key }}
+
{{ value }}
+
+
+ +
+
+
+ +
diff --git a/solr/webapp/web/partials/collection_overview.html b/solr/webapp/web/partials/collection_overview.html index ba09bd95fb8..cf1c18c3146 100644 --- a/solr/webapp/web/partials/collection_overview.html +++ b/solr/webapp/web/partials/collection_overview.html @@ -18,7 +18,7 @@ limitations under the License.
-
+

Collection: {{selectedCollection.name}}

diff --git a/solr/webapp/web/partials/collections.html b/solr/webapp/web/partials/collections.html index 60ef47ad0a1..198030c744f 100644 --- a/solr/webapp/web/partials/collections.html +++ b/solr/webapp/web/partials/collections.html @@ -18,77 +18,101 @@ limitations under the License. -
+
+
-
+
- - - - - - - -
- - - -

+

-

  +

  -

+

-

+

-

+

-

- Show advanced

-
+

+ Show advanced

+
-

Advanced options:

-

- -

- -

-

- -

-

- -

-

- -

- -

- -
-

- {{addMessage}} +

Advanced options:

+

+

-

- - +

+

+ +

+

+ +

+

+ +

+

- +
+

+ {{addMessage}} +

-
+

+ + +

+ + + +
+
+ +
+ + + +

+

+ +

+

+ + +

+ {{renameMessage}} +

+ +

+ + +

+
+ +
+
+ +
+ +
+ + + +
@@ -110,56 +134,15 @@ limitations under the License.
-
- -
- - - -

-

- -

-

- - -

- {{renameMessage}} -

- -

- - -

-
- -
-
- -

-

- -

- {{swapMessage}} -

+

Are you sure you want to delete alias {{ collection.name }}?

-
- -

No aliases to delete.

-

- -

-
-
@@ -168,12 +151,42 @@ limitations under the License.
-

Please select a collection

+

Please select a collection or alias

-
+
+ +

Alias: {{collection.name}}

+ +
+
+
+ +
+ +
    + +
  • +
    +
    Collections:
    +
    + + {{coll}}{{$last ? '' : ', '}} + +
    +
    +
    {{ key }}
    +
    {{ value }}
    +
    +
    +
  • +
+
+
+ +

Collection: {{collection.name}}

@@ -215,12 +228,21 @@ limitations under the License.
autoAddReplicas:
{{collection.autoAddReplicas}}
+ +
  • +
    aliases:
    +
    + + {{coll}}{{$last ? '' : ', '}} + +
    +
  • -