commit
This commit is contained in:
27
solr/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js
vendored
Normal file
27
solr/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js
vendored
Normal 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();
|
||||
});
|
||||
246
solr/server/solr-webapp/webapp/js/angular/controllers/analysis.js
vendored
Normal file
246
solr/server/solr-webapp/webapp/js/angular/controllers/analysis.js
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('AnalysisController',
|
||||
function($scope, $location, $routeParams, Luke, Analysis, Constants) {
|
||||
$scope.resetMenu("analysis", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
Luke.schema({core: $routeParams.core}, function(data) {
|
||||
$scope.fieldsAndTypes = getFieldsAndTypes(data.schema);
|
||||
$scope.core = $routeParams.core;
|
||||
$scope.parseQueryString(data.schema);
|
||||
// @todo - set defaultSearchField either to context["analysis.fieldname"] or context["analysis.fieldtype"]
|
||||
});
|
||||
};
|
||||
$scope.verbose = true;
|
||||
|
||||
var getFieldsAndTypes = function(schema) {
|
||||
var aggregatedFields = schema.fields;
|
||||
for (var field in schema.fields) {
|
||||
var copyDests = schema.fields[field].copyDests;
|
||||
for (var i in copyDests) {
|
||||
var copyDest = copyDests[i];
|
||||
if (!aggregatedFields[copyDest]) {
|
||||
aggregatedFields[copyDest] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fieldsAndTypes = [];
|
||||
var fields = Object.keys(aggregatedFields).sort();
|
||||
for (var i in fields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Fields",
|
||||
value: "fieldname=" + fields[i],
|
||||
label: fields[i]
|
||||
});
|
||||
}
|
||||
var dynamicFields = Object.keys(schema.dynamicFields).sort();
|
||||
for (var i in dynamicFields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Dynamic Fields",
|
||||
value: "dynamicfield=" + dynamicFields[i],
|
||||
label: dynamicFields[i]
|
||||
});
|
||||
}
|
||||
var types = Object.keys(schema.types).sort();
|
||||
for (var i in types) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Types",
|
||||
value: "fieldtype=" + types[i],
|
||||
label: types[i]
|
||||
});
|
||||
}
|
||||
return fieldsAndTypes;
|
||||
};
|
||||
|
||||
var getShortComponentName = function(longname) {
|
||||
var short = -1 !== longname.indexOf( '$' )
|
||||
? longname.split( '$' )[1]
|
||||
: longname.split( '.' ).pop();
|
||||
var match = short.match( /[A-Z]/g );
|
||||
if(match != undefined) {
|
||||
return match.join( '' );
|
||||
} else {
|
||||
return "?";
|
||||
}
|
||||
};
|
||||
|
||||
var getCaptionsForComponent = function(data) {
|
||||
var captions = [];
|
||||
for (var key in data[0]) {
|
||||
key = key.replace(/.*#/,'');
|
||||
if (key != "match" && key!="positionHistory") {
|
||||
captions.push(key.replace(/.*#/,''));
|
||||
}
|
||||
}
|
||||
return captions;
|
||||
};
|
||||
|
||||
var getTokensForComponent = function(data) {
|
||||
var tokens = [];
|
||||
var previousPosition = 0;
|
||||
var index=0;
|
||||
for (var i in data) {
|
||||
var tokenhash = data[i];
|
||||
var positionDifference = tokenhash.position - previousPosition;
|
||||
for (var j=positionDifference; j>1; j--) {
|
||||
tokens.push({position: tokenhash.position - j+1, blank:true, index:index++});
|
||||
}
|
||||
|
||||
var token = {position: tokenhash.position, keys:[], index:index++};
|
||||
|
||||
for (key in tokenhash) {
|
||||
if (key == "match" || key=="positionHistory") {
|
||||
//skip, to not display these keys in the UI
|
||||
} else {
|
||||
var tokenInfo = new Object();
|
||||
tokenInfo.name = key;
|
||||
tokenInfo.value = tokenhash[key];
|
||||
if ('text' === key || 'raw_bytes' === key ) {
|
||||
if (tokenhash.match) {
|
||||
tokenInfo.extraclass = 'match'; //to highlight matching text strings
|
||||
}
|
||||
}
|
||||
token.keys.push(tokenInfo);
|
||||
}
|
||||
}
|
||||
tokens.push(token);
|
||||
previousPosition = tokenhash.position;
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
var extractComponents = function(data, result, name) {
|
||||
if (data) {
|
||||
result[name] = [];
|
||||
for (var i = 0; i < data.length; i += 2) {
|
||||
var component = {
|
||||
name: data[i],
|
||||
short: getShortComponentName(data[i]),
|
||||
captions: getCaptionsForComponent(data[i + 1]),
|
||||
tokens: getTokensForComponent(data[i + 1])
|
||||
};
|
||||
result[name].push(component);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var processAnalysisData = function(analysis, fieldOrType) {
|
||||
var fieldname;
|
||||
for (fieldname in analysis[fieldOrType]) {console.log(fieldname);break;}
|
||||
var response = {};
|
||||
extractComponents(analysis[fieldOrType][fieldname].index, response, "index");
|
||||
extractComponents(analysis[fieldOrType][fieldname].query, response, "query");
|
||||
return response;
|
||||
};
|
||||
|
||||
$scope.updateQueryString = function() {
|
||||
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
var fieldOrType = parts[0];
|
||||
var name = parts[1];
|
||||
|
||||
if ($scope.indexText) {
|
||||
$location.search("analysis.fieldvalue", $scope.indexText);
|
||||
} else if ($location.search()["analysis.fieldvalue"]) {
|
||||
$location.search("analysis.fieldvalue", null);
|
||||
}
|
||||
if ($scope.queryText) {
|
||||
$location.search("analysis.query", $scope.queryText);
|
||||
} else if ($location.search()["analysis.query"]) {
|
||||
$location.search("analysis.query", null);
|
||||
}
|
||||
|
||||
if (fieldOrType == "fieldname") {
|
||||
$location.search("analysis.fieldname", name);
|
||||
$location.search("analysis.dynamicfield", null);
|
||||
$location.search("analysis.fieldtype", null);
|
||||
|
||||
} else if (fieldOrType == "dynamicfield") {
|
||||
$location.search("analysis.fieldname", null);
|
||||
$location.search("analysis.dynamicfield", name);
|
||||
$location.search("analysis.fieldtype", null);
|
||||
|
||||
} else {
|
||||
$location.search("analysis.fieldname", null);
|
||||
$location.search("analysis.dynamicfield", null);
|
||||
$location.search("analysis.fieldtype", name);
|
||||
}
|
||||
$location.search("verbose_output", $scope.verbose ? "1" : "0");
|
||||
};
|
||||
|
||||
$scope.parseQueryString = function (schema) {
|
||||
var params = {};
|
||||
var search = $location.search();
|
||||
|
||||
if (Object.keys(search).length == 0) {
|
||||
return;
|
||||
}
|
||||
for (var key in search) {
|
||||
params[key]=search[key];
|
||||
}
|
||||
$scope.indexText = search["analysis.fieldvalue"];
|
||||
$scope.queryText = search["analysis.query"];
|
||||
if (search["analysis.fieldname"]) {
|
||||
$scope.fieldOrType = "fieldname=" + search["analysis.fieldname"];
|
||||
$scope.schemaBrowserUrl = "field=" + search["analysis.fieldname"];
|
||||
} else if (search["analysis.dynamicfield"]) {
|
||||
params["analysis.fieldtype"] = schema.dynamicFields[search["analysis.dynamicfield"]].type;
|
||||
$scope.fieldOrType = "dynamicfield=" + search["analysis.dynamicfield"];
|
||||
$scope.schemaBrowserUrl = "dynamic-field=" + search["analysis.dynamicfield"];
|
||||
} else {
|
||||
$scope.fieldOrType = "fieldtype=" + search["analysis.fieldtype"];
|
||||
$scope.schemaBrowserUrl = "type=" + search["analysis.fieldtype"];
|
||||
}
|
||||
if (search["verbose_output"] == undefined) {
|
||||
$scope.verbose = true;
|
||||
} else {
|
||||
$scope.verbose = search["verbose_output"] == "1";
|
||||
}
|
||||
|
||||
if ($scope.fieldOrType || $scope.indexText || $scope.queryText) {
|
||||
params.core = $routeParams.core;
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
var fieldOrType = parts[0] == "fieldname" ? "field_names" : "field_types";
|
||||
|
||||
Analysis.field(params, function(data) {
|
||||
$scope.result = processAnalysisData(data.analysis, fieldOrType);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.changeFieldOrType = function() {
|
||||
var parts = $scope.fieldOrType.split("=");
|
||||
if (parts[0]=='fieldname') {
|
||||
$scope.schemaBrowserUrl = "field=" + parts[1];
|
||||
} else if (parts[0]=='dynamicfield') {
|
||||
$scope.schemaBrowserUrl = "dynamic-field=" + parts[1];
|
||||
} else {
|
||||
$scope.schemaBrowserUrl = "type=" + parts[1];
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleVerbose = function() {
|
||||
$scope.verbose = !$scope.verbose;
|
||||
$scope.updateQueryString();
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
1029
solr/server/solr-webapp/webapp/js/angular/controllers/cloud.js
vendored
Normal file
1029
solr/server/solr-webapp/webapp/js/angular/controllers/cloud.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
39
solr/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js
vendored
Normal file
39
solr/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CollectionOverviewController',
|
||||
function($scope, $routeParams, Collections, Constants) {
|
||||
$scope.resetMenu("collection-overview", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
Collections.status({}, function(data) {
|
||||
$scope.selectedCollection = data.cluster.collections[$routeParams.core];
|
||||
$scope.selectedCollection.name = $routeParams.core;
|
||||
$scope.rootUrl = Constants.ROOT_URL;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showReplica = function(replica) {
|
||||
replica.show = !replica.show;
|
||||
}
|
||||
|
||||
$scope.hideShard = function(shard) {
|
||||
shard.hide = !shard.hide;
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
306
solr/server/solr-webapp/webapp/js/angular/controllers/collections.js
vendored
Normal file
306
solr/server/solr-webapp/webapp/js/angular/controllers/collections.js
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CollectionsController',
|
||||
function($scope, $routeParams, $location, $timeout, Collections, CollectionsV2, Zookeeper, Constants, ConfigSets){
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
|
||||
$scope.rootUrl = Constants.ROOT_URL + "#/~collections/" + $routeParams.collection;
|
||||
|
||||
Zookeeper.liveNodes({}, function(data) {
|
||||
$scope.availableNodeSet = [];
|
||||
var children = data.tree[0].children;
|
||||
for (var child in children) {
|
||||
$scope.availableNodeSet.push(children[child].text);
|
||||
}
|
||||
});
|
||||
|
||||
Collections.status(function (data) {
|
||||
$scope.collections = [];
|
||||
for (var name in data.cluster.collections) {
|
||||
if (name.startsWith("._designer_")) {
|
||||
continue;
|
||||
}
|
||||
var collection = data.cluster.collections[name];
|
||||
collection.name = name;
|
||||
collection.type = 'collection';
|
||||
var shards = collection.shards;
|
||||
collection.shards = [];
|
||||
for (var shardName in shards) {
|
||||
var shard = shards[shardName];
|
||||
shard.name = shardName;
|
||||
shard.collection = collection.name;
|
||||
var replicas = shard.replicas;
|
||||
shard.replicas = [];
|
||||
for (var replicaName in replicas) {
|
||||
var replica = replicas[replicaName];
|
||||
replica.name = replicaName;
|
||||
replica.collection = collection.name;
|
||||
replica.shard = shard.name;
|
||||
shard.replicas.push(replica);
|
||||
}
|
||||
collection.shards.push(shard);
|
||||
}
|
||||
$scope.collections.push(collection);
|
||||
if ($routeParams.collection == name) {
|
||||
$scope.collection = collection;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
});
|
||||
ConfigSets.configs(function(data) {
|
||||
$scope.configs = [];
|
||||
var items = data.configSets;
|
||||
for (var i in items) {
|
||||
$scope.configs.push({name: items[i]});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showRename = false;
|
||||
$scope.showAdd = false;
|
||||
$scope.showDelete = false;
|
||||
$scope.showSwap = false;
|
||||
$scope.showCreateAlias = false;
|
||||
$scope.showDeleteAlias = false;
|
||||
};
|
||||
|
||||
$scope.showAddCollection = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showAdd = true;
|
||||
$scope.newCollection = {
|
||||
name: "",
|
||||
routerName: "compositeId",
|
||||
numShards: 1,
|
||||
configName: "",
|
||||
nrtReplicas: 0,
|
||||
tlogReplicas: 0,
|
||||
pullReplicas: 0,
|
||||
replicationFactor: 1
|
||||
};
|
||||
};
|
||||
|
||||
$scope.toggleCreateAlias = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showCreateAlias = true;
|
||||
}
|
||||
|
||||
$scope.toggleDeleteAlias = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showDeleteAlias = true;
|
||||
}
|
||||
|
||||
$scope.cancelCreateAlias = $scope.cancelDeleteAlias = function() {
|
||||
$scope.hideAll();
|
||||
}
|
||||
|
||||
$scope.createAlias = function() {
|
||||
var collections = [];
|
||||
for (var i in $scope.aliasCollections) {
|
||||
collections.push($scope.aliasCollections[i].name);
|
||||
}
|
||||
Collections.createAlias({name: $scope.aliasToCreate, collections: collections.join(",")}, function(data) {
|
||||
$scope.cancelCreateAlias();
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
$location.path("/~collections/alias_" + $scope.aliasToCreate);
|
||||
});
|
||||
}
|
||||
$scope.deleteAlias = function() {
|
||||
Collections.deleteAlias({name: $scope.collection.name}, function(data) {
|
||||
$scope.hideAll();
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
$location.path("/~collections/");
|
||||
});
|
||||
|
||||
};
|
||||
$scope.addCollection = function() {
|
||||
if (!$scope.newCollection.name) {
|
||||
$scope.addMessage = "Please provide a core name";
|
||||
} else if (false) { //@todo detect whether core exists
|
||||
$scope.AddMessage = "A core with that name already exists";
|
||||
} else if ( $scope.newCollection.pullReplicas > 0 && ($scope.newCollection.nrtReplicas + $scope.newCollection.tlogReplicas == 0))
|
||||
{
|
||||
$scope.addMessage = "A collection can't be made up of just PULL replicas";
|
||||
} else {
|
||||
var coll = $scope.newCollection;
|
||||
var params = {
|
||||
name: coll.name,
|
||||
"router.name": coll.routerName,
|
||||
numShards: coll.numShards,
|
||||
"collection.configName": coll.configName
|
||||
};
|
||||
if (coll.shards) params.shards = coll.shards;
|
||||
if (coll.routerField) params["router.field"] = coll.routerField;
|
||||
if (coll.createNodeSet) params.createNodeSet = coll.createNodeSet.join(",");
|
||||
if ($scope.replicaTypesChosen()) {
|
||||
params["nrtReplicas"] = coll.nrtReplicas;
|
||||
params["tlogReplicas"] = coll.tlogReplicas;
|
||||
params["pullReplicas"] = coll.pullReplicas;
|
||||
} else {
|
||||
params["replicationFactor"] = coll.replicationFactor;
|
||||
}
|
||||
Collections.add(params, function(data) {
|
||||
$scope.cancelAddCollection();
|
||||
$scope.resetMenu("collections", Constants.IS_ROOT_PAGE);
|
||||
$location.path("/~collections/" + $scope.newCollection.name);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelAddCollection = function() {
|
||||
delete $scope.addMessage;
|
||||
$scope.showAdd = false;
|
||||
};
|
||||
|
||||
$scope.showDeleteCollection = function() {
|
||||
$scope.hideAll();
|
||||
if ($scope.collection) {
|
||||
$scope.showDelete = true;
|
||||
} else {
|
||||
alert("No collection selected.");
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteCollection = function() {
|
||||
if ($scope.collection.name == $scope.collectionDeleteConfirm) {
|
||||
Collections.delete({name: $scope.collection.name}, function (data) {
|
||||
$location.path("/~collections");
|
||||
});
|
||||
} else {
|
||||
$scope.deleteMessage = "Collection names do not match.";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.reloadCollection = function() {
|
||||
if (!$scope.collection) {
|
||||
alert("No collection selected.");
|
||||
return;
|
||||
}
|
||||
CollectionsV2.reloadCollection($scope.collection.name, function(error, data,response) {
|
||||
if (error) {
|
||||
$scope.reloadFailure = true;
|
||||
$timeout(function() {$scope.reloadFailure=false}, 1000);
|
||||
$location.path("/~collections");
|
||||
} else {
|
||||
$scope.reloadSuccess = true;
|
||||
$timeout(function() {$scope.reloadSuccess=false}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleAddReplica = function(shard) {
|
||||
$scope.hideAll();
|
||||
shard.showAdd = !shard.showAdd;
|
||||
delete $scope.addReplicaMessage;
|
||||
|
||||
Zookeeper.liveNodes({}, function(data) {
|
||||
$scope.nodes = [];
|
||||
var children = data.tree[0].children;
|
||||
for (var child in children) {
|
||||
$scope.nodes.push(children[child].text);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleRemoveReplica = function(replica) {
|
||||
$scope.hideAll();
|
||||
replica.showRemove = !replica.showRemove;
|
||||
};
|
||||
|
||||
$scope.toggleRemoveShard = function(shard) {
|
||||
$scope.hideAll();
|
||||
shard.showRemove = !shard.showRemove;
|
||||
};
|
||||
|
||||
$scope.deleteShard = function(shard) {
|
||||
Collections.deleteShard({collection: shard.collection, shard:shard.name}, function(data) {
|
||||
shard.deleted = true;
|
||||
$timeout(function() {
|
||||
$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteReplica = function(replica) {
|
||||
Collections.deleteReplica({collection: replica.collection, shard:replica.shard, replica:replica.name}, function(data) {
|
||||
replica.deleted = true;
|
||||
$timeout(function() {
|
||||
$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
$scope.addReplica = function(shard) {
|
||||
var params = {
|
||||
collection: shard.collection,
|
||||
shard: shard.name,
|
||||
type: shard.replicaType
|
||||
}
|
||||
if (shard.replicaNodeName && shard.replicaNodeName != "") {
|
||||
params.node = shard.replicaNodeName;
|
||||
}
|
||||
Collections.addReplica(params, function(data) {
|
||||
shard.replicaAdded = true;
|
||||
$timeout(function () {
|
||||
shard.replicaAdded = false;
|
||||
shard.showAdd = false;
|
||||
$scope.refresh();
|
||||
}, 2000);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleShard = function(shard) {
|
||||
shard.show = !shard.show;
|
||||
}
|
||||
|
||||
$scope.toggleReplica = function(replica) {
|
||||
replica.show = !replica.show;
|
||||
}
|
||||
|
||||
$scope.replicaTypesChosen = function () {
|
||||
if ($scope.newCollection) {
|
||||
return ( $scope.newCollection.nrtReplicas + $scope.newCollection.tlogReplicas + $scope.newCollection.pullReplicas > 0 );
|
||||
}
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
95
solr/server/solr-webapp/webapp/js/angular/controllers/core-overview.js
vendored
Normal file
95
solr/server/solr-webapp/webapp/js/angular/controllers/core-overview.js
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CoreOverviewController',
|
||||
function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication, Ping, Constants) {
|
||||
$scope.resetMenu("overview", Constants.IS_CORE_PAGE);
|
||||
$scope.refreshIndex = function() {
|
||||
Luke.index({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.index = data.index;
|
||||
delete $scope.statsMessage;
|
||||
},
|
||||
function(error) {
|
||||
$scope.statsMessage = "Luke is not configured";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.refreshReplication = function() {
|
||||
Replication.details({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.isFollower = data.details.isFollower == "true";
|
||||
$scope.isLeader = data.details.isLeader == "true";
|
||||
$scope.replication = data.details;
|
||||
},
|
||||
function(error) {
|
||||
$scope.replicationMessage = "Replication is not configured";
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refreshSystem = function() {
|
||||
CoreSystem.get({core: $routeParams.core},
|
||||
function(data) {
|
||||
$scope.core = data.core;
|
||||
delete $scope.systemMessage;
|
||||
},
|
||||
function(error) {
|
||||
$scope.systemMessage = "/admin/system Handler is not configured";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.refreshPing = function() {
|
||||
Ping.status({core: $routeParams.core}, function(data) {
|
||||
if (data.error) {
|
||||
$scope.healthcheckStatus = false;
|
||||
if (data.error.code == 503) {
|
||||
$scope.healthcheckMessage = 'Ping request handler is not configured with a healthcheck file.';
|
||||
}
|
||||
} else {
|
||||
$scope.healthcheckStatus = data.status == "enabled";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleHealthcheck = function() {
|
||||
if ($scope.healthcheckStatus) {
|
||||
Ping.disable(
|
||||
{core: $routeParams.core},
|
||||
function(data) {$scope.healthcheckStatus = false},
|
||||
function(error) {$scope.healthcheckMessage = error}
|
||||
);
|
||||
} else {
|
||||
Ping.enable(
|
||||
{core: $routeParams.core},
|
||||
function(data) {$scope.healthcheckStatus = true},
|
||||
function(error) {$scope.healthcheckMessage = error}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.refresh = function() {
|
||||
$scope.refreshIndex();
|
||||
$scope.refreshReplication();
|
||||
$scope.refreshSystem();
|
||||
$scope.refreshPing();
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
180
solr/server/solr-webapp/webapp/js/angular/controllers/cores.js
vendored
Normal file
180
solr/server/solr-webapp/webapp/js/angular/controllers/cores.js
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('CoreAdminController',
|
||||
function($scope, $routeParams, $location, $timeout, $route, Cores, Update, Constants){
|
||||
$scope.resetMenu("cores", Constants.IS_ROOT_PAGE);
|
||||
$scope.selectedCore = $routeParams.corename; // use 'corename' not 'core' to distinguish from /solr/:core/
|
||||
$scope.refresh = function() {
|
||||
Cores.get(function(data) {
|
||||
var coreCount = 0;
|
||||
var cores = data.status;
|
||||
for (_obj in cores) coreCount++;
|
||||
$scope.hasCores = coreCount >0;
|
||||
if (!$scope.selectedCore && coreCount==0) {
|
||||
$scope.showAddCore();
|
||||
return;
|
||||
} else if (!$scope.selectedCore) {
|
||||
for (firstCore in cores) break;
|
||||
$scope.selectedCore = firstCore;
|
||||
$location.path("/~cores/" + $scope.selectedCore).replace();
|
||||
}
|
||||
$scope.core = cores[$scope.selectedCore];
|
||||
$scope.corelist = [];
|
||||
$scope.swapCorelist = [];
|
||||
for (var core in cores) {
|
||||
$scope.corelist.push(cores[core]);
|
||||
if (cores[core] != $scope.core) {
|
||||
$scope.swapCorelist.push(cores[core]);
|
||||
}
|
||||
}
|
||||
if ($scope.swapCorelist.length>0) {
|
||||
$scope.swapOther = $scope.swapCorelist[0].name;
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.showAddCore = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showAdd = true;
|
||||
$scope.newCore = {
|
||||
name: "new_core",
|
||||
dataDir: "data",
|
||||
instanceDir: "new_core",
|
||||
config: "solrconfig.xml",
|
||||
schema: "schema.xml",
|
||||
collection: "",
|
||||
shard: ""
|
||||
};
|
||||
};
|
||||
|
||||
$scope.addCore = function() {
|
||||
if (!$scope.newCore.name) {
|
||||
$scope.addMessage = "Please provide a core name";
|
||||
} else if (false) { //@todo detect whether core exists
|
||||
$scope.AddMessage = "A core with that name already exists";
|
||||
} else {
|
||||
var params = {
|
||||
name: $scope.newCore.name,
|
||||
instanceDir: $scope.newCore.instanceDir,
|
||||
config: $scope.newCore.config,
|
||||
schema: $scope.newCore.schema,
|
||||
dataDir: $scope.newCore.dataDir
|
||||
};
|
||||
if ($scope.isCloud) {
|
||||
params.collection = $scope.newCore.collection;
|
||||
params.shard = $scope.newCore.shard;
|
||||
}
|
||||
Cores.add(params, function(data) {
|
||||
$location.path("/~cores/" + $scope.newCore.name);
|
||||
$scope.cancelAddCore();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelAddCore = function() {
|
||||
delete $scope.addMessage;
|
||||
$scope.showAdd = false
|
||||
};
|
||||
|
||||
$scope.unloadCore = function() {
|
||||
var answer = confirm( 'Do you really want to unload Core "' + $scope.selectedCore + '"?' );
|
||||
if( !answer ) return;
|
||||
Cores.unload({core: $scope.selectedCore}, function(data) {
|
||||
$location.path("/~cores");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showRenameCore = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showRename = true;
|
||||
};
|
||||
|
||||
$scope.renameCore = function() {
|
||||
if (!$scope.other) {
|
||||
$scope.renameMessage = "Please provide a new name for the " + $scope.selectedCore + " core";
|
||||
} else if ($scope.other == $scope.selectedCore) {
|
||||
$scope.renameMessage = "New name must be different from the current one";
|
||||
} else {
|
||||
Cores.rename({core:$scope.selectedCore, other: $scope.other}, function(data) {
|
||||
$location.path("/~cores/" + $scope.other);
|
||||
$scope.cancelRename();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelRenameCore = function() {
|
||||
$scope.showRename = false;
|
||||
delete $scope.renameMessage;
|
||||
$scope.other = "";
|
||||
};
|
||||
|
||||
$scope.showSwapCores = function() {
|
||||
$scope.hideAll();
|
||||
$scope.showSwap = true;
|
||||
};
|
||||
|
||||
$scope.swapCores = function() {
|
||||
if (!$scope.swapOther) {
|
||||
$scope.swapMessage = "Please select a core to swap with";
|
||||
} else if ($scope.swapOther == $scope.selectedCore) {
|
||||
$scope.swapMessage = "Cannot swap with the same core";
|
||||
} else {
|
||||
Cores.swap({core: $scope.selectedCore, other: $scope.swapOther}, function(data) {
|
||||
$location.path("/~cores/" + $scope.swapOther);
|
||||
delete $scope.swapOther;
|
||||
$scope.cancelSwapCores();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelSwapCores = function() {
|
||||
delete $scope.swapMessage;
|
||||
$scope.showSwap = false;
|
||||
}
|
||||
|
||||
$scope.reloadCore = function() {
|
||||
if ($scope.initFailures[$scope.selectedCore]) {
|
||||
delete $scope.initFailures[$scope.selectedCore];
|
||||
$scope.showInitFailures = Object.keys(data.initFailures).length>0;
|
||||
}
|
||||
Cores.reload({core: $scope.selectedCore},
|
||||
function(data) {
|
||||
if (data.error) {
|
||||
$scope.reloadFailure = true;
|
||||
$timeout(function() {
|
||||
$scope.reloadFailure = false;
|
||||
$route.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
$scope.reloadSuccess = true;
|
||||
$timeout(function () {
|
||||
$scope.reloadSuccess = false;
|
||||
$route.reload();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showRename = false;
|
||||
$scope.showAdd = false;
|
||||
$scope.showSwap = false;
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
}
|
||||
);
|
||||
137
solr/server/solr-webapp/webapp/js/angular/controllers/documents.js
vendored
Normal file
137
solr/server/solr-webapp/webapp/js/angular/controllers/documents.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
//helper for formatting JSON and others
|
||||
|
||||
var DOC_PLACEHOLDER = '<doc>\n' +
|
||||
'<field name="id">change.me</field>' +
|
||||
'<field name="title">change.me</field>' +
|
||||
'</doc>';
|
||||
|
||||
var ADD_PLACEHOLDER = '<add>\n' + DOC_PLACEHOLDER + '</add>\n';
|
||||
|
||||
solrAdminApp.controller('DocumentsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Luke, Update, FileUpload, Constants) {
|
||||
$scope.resetMenu("documents", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Luke.schema({core: $routeParams.core}, function(data) {
|
||||
//TODO: handle dynamic fields
|
||||
delete data.schema.fields._version_;
|
||||
$scope.fields = Object.keys(data.schema.fields);
|
||||
});
|
||||
$scope.document = "";
|
||||
$scope.handler = "/update";
|
||||
$scope.type = "json";
|
||||
$scope.commitWithin = 1000;
|
||||
$scope.overwrite = true;
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
|
||||
$scope.changeDocumentType = function () {
|
||||
$scope.placeholder = "";
|
||||
if ($scope.type == 'json') {
|
||||
$scope.placeholder = '{"id":"change.me","title":"change.me"}';
|
||||
} else if ($scope.type == 'csv') {
|
||||
$scope.placeholder = "id,title\nchange.me,change.me";
|
||||
} else if ($scope.type == 'solr') {
|
||||
$scope.placeholder = ADD_PLACEHOLDER;
|
||||
} else if ($scope.type == 'xml') {
|
||||
$scope.placeholder = DOC_PLACEHOLDER;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addWizardField = function () {
|
||||
if ($scope.document == "") $scope.document = "{}";
|
||||
var doc = JSON.parse($scope.document);
|
||||
doc[$scope.fieldName] = $scope.fieldData;
|
||||
$scope.document = JSON.stringify(doc, null, '\t');
|
||||
$scope.fieldData = "";
|
||||
};
|
||||
|
||||
$scope.submit = function () {
|
||||
var contentType = "";
|
||||
var postData = "";
|
||||
var params = {};
|
||||
var doingFileUpload = false;
|
||||
|
||||
if ($scope.handler[0] == '/') {
|
||||
params.handler = $scope.handler.substring(1);
|
||||
} else {
|
||||
params.handler = 'update';
|
||||
params.qt = $scope.handler;
|
||||
}
|
||||
|
||||
params.commitWithin = $scope.commitWithin;
|
||||
params.overwrite = $scope.overwrite;
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
|
||||
if ($scope.type == "json" || $scope.type == "wizard") {
|
||||
postData = "[" + $scope.document + "]";
|
||||
contentType = "json";
|
||||
} else if ($scope.type == "csv") {
|
||||
postData = $scope.document;
|
||||
contentType = "csv";
|
||||
} else if ($scope.type == "xml") {
|
||||
postData = "<add>" + $scope.document + "</add>";
|
||||
contentType = "xml";
|
||||
} else if ($scope.type == "upload") {
|
||||
doingFileUpload = true;
|
||||
params.raw = $scope.literalParams;
|
||||
} else if ($scope.type == "solr") {
|
||||
postData = $scope.document;
|
||||
if (postData[0] == "<") {
|
||||
contentType = "xml";
|
||||
} else if (postData[0] == "{" || postData[0] == '[') {
|
||||
contentType = "json";
|
||||
} else {
|
||||
alert("Cannot identify content type")
|
||||
}
|
||||
}
|
||||
if (!doingFileUpload) {
|
||||
var callback = function (success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
};
|
||||
var failure = function (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
};
|
||||
if (contentType == "json") {
|
||||
Update.postJson(params, postData, callback, failure);
|
||||
} else if (contentType == "xml") {
|
||||
Update.postXml(params, postData, callback, failure);
|
||||
} else if (contentType == "csv") {
|
||||
Update.postCsv(params, postData, callback, failure);
|
||||
}
|
||||
} else {
|
||||
var file = $scope.fileUpload;
|
||||
console.log('file is ' + JSON.stringify(file));
|
||||
var uploadUrl = "/fileUpload";
|
||||
FileUpload.upload(params, $scope.fileUpload, function (success) {
|
||||
$scope.responseStatus = "success";
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
}, function (failure) {
|
||||
$scope.responseStatus = "failure";
|
||||
$scope.response = JSON.stringify(failure, null, ' ');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
98
solr/server/solr-webapp/webapp/js/angular/controllers/files.js
vendored
Normal file
98
solr/server/solr-webapp/webapp/js/angular/controllers/files.js
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var contentTypeMap = { xml : 'application/xml', html : 'application/xml', js : 'application/javascript', json : 'application/json', css : 'text/plain' };
|
||||
var languages = {js: "javascript", xml:"xml", xsl:"xml", vm: "xml", html: "xml", json: "json"};
|
||||
|
||||
solrAdminApp.controller('FilesController',
|
||||
function($scope, $rootScope, $routeParams, $location, Files, Constants) {
|
||||
$scope.resetMenu("files", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.file = $location.search().file;
|
||||
$scope.content = null;
|
||||
|
||||
$scope.baseurl = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // Including /solr/ context
|
||||
|
||||
$scope.refresh = function () {
|
||||
|
||||
var process = function (path, tree) {
|
||||
var params = {core: $routeParams.core};
|
||||
if (path.slice(-1) === '/') {
|
||||
params.file = path.slice(0, -1);
|
||||
} else if (path!=='') {
|
||||
params.file = path;
|
||||
}
|
||||
|
||||
Files.list(params, function (data) {
|
||||
var filenames = Object.keys(data.files);
|
||||
filenames.sort();
|
||||
for (var i in filenames) {
|
||||
var file = filenames[i];
|
||||
var filedata = data.files[file];
|
||||
var state = undefined;
|
||||
var children = undefined;
|
||||
|
||||
if (filedata.directory) {
|
||||
file = file + "/";
|
||||
if ($scope.file && $scope.file.indexOf(path + file) === 0) {
|
||||
state = {"opened": true};
|
||||
} else {
|
||||
state = {"opened": false};
|
||||
}
|
||||
children = [];
|
||||
process(path + file, children);
|
||||
}
|
||||
tree.push({
|
||||
text: file,
|
||||
a_attr: { id: path + file},
|
||||
children: children,
|
||||
state: state
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.tree = [];
|
||||
process("", $scope.tree);
|
||||
|
||||
if ($scope.file && $scope.file !== '' && $scope.file.split('').pop()!=='/') {
|
||||
var extension;
|
||||
if ($scope.file === "managed-schema") {
|
||||
extension = 'xml';
|
||||
} else {
|
||||
extension = $scope.file.match( /\.(\w+)$/)[1] || '';
|
||||
}
|
||||
var contentType = (contentTypeMap[extension] || 'text/plain' ) + ';charset=utf-8';
|
||||
|
||||
Files.get({core: $routeParams.core, file: $scope.file, contentType: contentType}, function(data) {
|
||||
$scope.content = data.data;
|
||||
$scope.url = data.config.url + "?" + $.param(data.config.params); // relative URL
|
||||
if (contentType.indexOf("text/plain") && (data.data.indexOf("<?xml")>=0) || data.data.indexOf("<!--")>=0) {
|
||||
$scope.lang = "xml";
|
||||
} else {
|
||||
$scope.lang = languages[extension] || "txt";
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showTreeLink = function(data) {
|
||||
var file = data.node.a_attr.id;
|
||||
$location.search({file:file});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
125
solr/server/solr-webapp/webapp/js/angular/controllers/index.js
vendored
Normal file
125
solr/server/solr-webapp/webapp/js/angular/controllers/index.js
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('IndexController', function($scope, System, Cores, Constants) {
|
||||
$scope.resetMenu("index", Constants.IS_ROOT_PAGE);
|
||||
$scope.reload = function() {
|
||||
System.get(function(data) {
|
||||
$scope.system = data;
|
||||
const releaseDate = parse_release_date($scope.system.lucene['solr-impl-version'])
|
||||
$scope.releaseDaysOld = (new Date() - releaseDate)/1000/60/60/24;
|
||||
|
||||
if ("username" in data.security) {
|
||||
// Needed for Kerberos, since this is the only place from where
|
||||
// Kerberos username can be obtained.
|
||||
sessionStorage.setItem("auth.username", data.security.username);
|
||||
}
|
||||
|
||||
if (data.security.authenticationPlugin) {
|
||||
$scope.isSecurityEnabled = true
|
||||
}
|
||||
|
||||
// load average, unless its negative (means n/a on windows, etc)
|
||||
if (data.system.systemLoadAverage >= 0) {
|
||||
$scope.load_average = data.system.systemLoadAverage.toFixed(2);
|
||||
}
|
||||
|
||||
// physical memory
|
||||
var memoryMax = parse_memory_value(data.system.totalPhysicalMemorySize);
|
||||
$scope.memoryTotal = parse_memory_value(data.system.totalPhysicalMemorySize - data.system.freePhysicalMemorySize);
|
||||
$scope.memoryPercentage = ($scope.memoryTotal / memoryMax * 100).toFixed(1)+ "%";
|
||||
$scope.memoryMax = pretty_print_bytes(memoryMax);
|
||||
$scope.memoryTotalDisplay = pretty_print_bytes($scope.memoryTotal);
|
||||
|
||||
// swap space
|
||||
var swapMax = parse_memory_value(data.system.totalSwapSpaceSize);
|
||||
$scope.swapTotal = parse_memory_value(data.system.totalSwapSpaceSize - data.system.freeSwapSpaceSize);
|
||||
$scope.swapPercentage = ($scope.swapTotal / swapMax * 100).toFixed(1)+ "%";
|
||||
$scope.swapMax = pretty_print_bytes(swapMax);
|
||||
$scope.swapTotalDisplay = pretty_print_bytes($scope.swapTotal);
|
||||
|
||||
// file handles
|
||||
$scope.fileDescriptorPercentage = (data.system.openFileDescriptorCount / data.system.maxFileDescriptorCount *100).toFixed(1) + "%";
|
||||
|
||||
// java memory
|
||||
var javaMemoryMax = parse_memory_value(data.jvm.memory.raw.max || data.jvm.memory.max);
|
||||
$scope.javaMemoryTotal = parse_memory_value(data.jvm.memory.raw.total || data.jvm.memory.total);
|
||||
$scope.javaMemoryUsed = parse_memory_value(data.jvm.memory.raw.used || data.jvm.memory.used);
|
||||
$scope.javaMemoryTotalPercentage = ($scope.javaMemoryTotal / javaMemoryMax *100).toFixed(1) + "%";
|
||||
$scope.javaMemoryUsedPercentage = ($scope.javaMemoryUsed / $scope.javaMemoryTotal *100).toFixed(1) + "%";
|
||||
$scope.javaMemoryPercentage = ($scope.javaMemoryUsed / javaMemoryMax * 100).toFixed(1) + "%";
|
||||
$scope.javaMemoryTotalDisplay = pretty_print_bytes($scope.javaMemoryTotal);
|
||||
$scope.javaMemoryUsedDisplay = pretty_print_bytes($scope.javaMemoryUsed); // @todo These should really be an AngularJS Filter: {{ javaMemoryUsed | bytes }}
|
||||
$scope.javaMemoryMax = pretty_print_bytes(javaMemoryMax);
|
||||
|
||||
// no info bar:
|
||||
$scope.noInfo = !(
|
||||
data.system.totalPhysicalMemorySize && data.system.freePhysicalMemorySize &&
|
||||
data.system.totalSwapSpaceSize && data.system.freeSwapSpaceSize &&
|
||||
data.system.openFileDescriptorCount && data.system.maxFileDescriptorCount);
|
||||
|
||||
// save a copy of the original commandline args
|
||||
$scope.commandLineArgsUnsorted = [...data.jvm.jmx.commandLineArgs];
|
||||
// get commandline args latest orderby or defaults to "Unsorted"
|
||||
$scope.commandLineOrderBy = sessionStorage.getItem("commandline.orderby") || "Unsorted";
|
||||
$scope.showCommandLineArgs();
|
||||
});
|
||||
};
|
||||
$scope.toggleCommandLineOrder = function() {
|
||||
$scope.commandLineOrderBy = ($scope.commandLineOrderBy=="Sorted") ? "Unsorted":"Sorted";
|
||||
sessionStorage.setItem("commandline.orderby", $scope.commandLineOrderBy);
|
||||
$scope.showCommandLineArgs();
|
||||
}
|
||||
$scope.showCommandLineArgs = function() {
|
||||
if ($scope.commandLineOrderBy == "Sorted") {
|
||||
$scope.commandLineArgs = [...$scope.commandLineArgsUnsorted].sort();
|
||||
} else {
|
||||
$scope.commandLineArgs = $scope.commandLineArgsUnsorted;
|
||||
}
|
||||
}
|
||||
$scope.reload();
|
||||
});
|
||||
|
||||
var parse_memory_value = function( value ) {
|
||||
if( value !== Number( value ) )
|
||||
{
|
||||
var units = 'BKMGTPEZY';
|
||||
var match = value.match( /^(\d+([,\.]\d+)?) (\w).*$/ );
|
||||
var value = parseFloat( match[1] ) * Math.pow( 1024, units.indexOf( match[3].toUpperCase() ) );
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
const parse_release_date = function(value) {
|
||||
const match = value.match( /.* (20\d\d-[0-1]\d-[0-3]\d) .*/ );
|
||||
return match === null ? new Date() : new Date(match[1]);
|
||||
};
|
||||
|
||||
var pretty_print_bytes = function(byte_value) {
|
||||
var unit = null;
|
||||
|
||||
byte_value /= 1024;
|
||||
byte_value /= 1024;
|
||||
unit = 'MB';
|
||||
|
||||
if( 1024 <= byte_value ) {
|
||||
byte_value /= 1024;
|
||||
unit = 'GB';
|
||||
}
|
||||
return byte_value.toFixed( 2 ) + ' ' + unit;
|
||||
};
|
||||
45
solr/server/solr-webapp/webapp/js/angular/controllers/java-properties.js
vendored
Normal file
45
solr/server/solr-webapp/webapp/js/angular/controllers/java-properties.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('JavaPropertiesController',
|
||||
function($scope, Properties, Constants){
|
||||
$scope.resetMenu("java-props", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Properties.get(function(data) {
|
||||
var sysprops = data["system.properties"];
|
||||
var sep = sysprops["path.separator"]
|
||||
var props = [];
|
||||
for (var key in sysprops) {
|
||||
var value = sysprops[key];
|
||||
var values = value.split(sep);
|
||||
if (value === sep) {
|
||||
values = [':'];
|
||||
}
|
||||
props.push({
|
||||
name: key.replace(/\./g, '.​')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>'),
|
||||
values: values
|
||||
});
|
||||
}
|
||||
$scope.pathSeparator = sep;
|
||||
$scope.props = props;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
164
solr/server/solr-webapp/webapp/js/angular/controllers/logging.js
vendored
Normal file
164
solr/server/solr-webapp/webapp/js/angular/controllers/logging.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var format_time_content = function( time, timeZone ) {
|
||||
var format_time_options = {};
|
||||
if (timeZone && timeZone!="Local") {
|
||||
format_time_options.timeZone = timeZone;
|
||||
}
|
||||
return time.toLocaleString( undefined, format_time_options );
|
||||
}
|
||||
|
||||
solrAdminApp.controller('LoggingController',
|
||||
function($scope, $timeout, $cookies, Logging, Constants){
|
||||
$scope.resetMenu("logging", Constants.IS_ROOT_PAGE);
|
||||
$scope.timezone = $cookies.logging_timezone || "Local";
|
||||
$scope.refresh = function() {
|
||||
Logging.events(function(data) {
|
||||
$scope.since = new Date();
|
||||
$scope.sinceDisplay = format_time_content($scope.since, "Local");
|
||||
var events = data.history.docs;
|
||||
for (var i=0; i<events.length; i++) {
|
||||
var event = events[i];
|
||||
var time = new Date(event.time);
|
||||
event.local_time = format_time_content(time, "Local");
|
||||
event.utc_time = format_time_content(time, "UTC");
|
||||
event.loggerBase = event.logger.split( '.' ).pop();
|
||||
|
||||
if( !event.trace ) {
|
||||
var lines = event.message.split( "\n" );
|
||||
if( lines.length > 1) {
|
||||
event.trace = event.message;
|
||||
event.message = lines[0];
|
||||
}
|
||||
}
|
||||
event.message = event.message.replace(/,/g, ',​');
|
||||
event.showTrace = false;
|
||||
}
|
||||
$scope.events = events;
|
||||
$scope.watcher = data.watcher;
|
||||
/* @todo sticky_mode
|
||||
// state element is in viewport
|
||||
sticky_mode = ( state.position().top <= $( window ).scrollTop() + $( window ).height() - ( $( 'body' ).height() - state.position().top ) );
|
||||
// initial request
|
||||
if( 0 === since ) {
|
||||
sticky_mode = true;
|
||||
}
|
||||
$scope.loggingEvents = events;
|
||||
|
||||
if( sticky_mode )
|
||||
{
|
||||
$( 'body' )
|
||||
.animate
|
||||
(
|
||||
{ scrollTop: state.position().top },
|
||||
1000
|
||||
);
|
||||
}
|
||||
*/
|
||||
});
|
||||
$scope.timeout = $timeout($scope.refresh, 10000);
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
$timeout.cancel($scope.timeout);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
};
|
||||
$scope.refresh();
|
||||
$scope.toggleRefresh = function() {
|
||||
if(!$scope.stopped) {
|
||||
$scope.stopped = true;
|
||||
$timeout.cancel($scope.timeout);
|
||||
} else {
|
||||
$scope.stopped = false;
|
||||
$scope.timeout = $timeout($scope.refresh, 10000);
|
||||
}
|
||||
};
|
||||
$scope.toggleTimezone = function() {
|
||||
$scope.timezone = ($scope.timezone=="Local") ? "UTC":"Local";
|
||||
$cookies.logging_timezone = $scope.timezone;
|
||||
}
|
||||
$scope.toggleRow = function(event) {
|
||||
event.showTrace =! event.showTrace;
|
||||
};
|
||||
}
|
||||
)
|
||||
|
||||
.controller('LoggingLevelController',
|
||||
function($scope, Logging) {
|
||||
$scope.resetMenu("logging-levels");
|
||||
|
||||
var packageOf = function(logger) {
|
||||
var parts = logger.name.split(".");
|
||||
return !parts.pop() ? "" : parts.join(".");
|
||||
};
|
||||
|
||||
var shortNameOf = function(logger) {return logger.name.split(".").pop();}
|
||||
|
||||
var makeTree = function(loggers, packag) {
|
||||
var tree = [];
|
||||
for (var i=0; i<loggers.length; i++) {
|
||||
var logger = loggers[i];
|
||||
logger.packag = packageOf(logger);
|
||||
logger.short = shortNameOf(logger);
|
||||
if (logger.packag == packag) {
|
||||
logger.children = makeTree(loggers, logger.name);
|
||||
tree.push(logger);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
};
|
||||
|
||||
$scope.refresh = function() {
|
||||
Logging.levels(function(data) {
|
||||
$scope.logging = makeTree(data.loggers, "");
|
||||
$scope.watcher = data.watcher;
|
||||
$scope.levels = [];
|
||||
for (level in data.levels) {
|
||||
$scope.levels.push({name:data.levels[level], pos:level});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleOptions = function(logger) {
|
||||
if (!$scope.isPermitted(permissions.CONFIG_EDIT_PERM)) {
|
||||
return;
|
||||
}
|
||||
if (logger.showOptions) {
|
||||
logger.showOptions = false;
|
||||
delete $scope.currentLogger;
|
||||
} else {
|
||||
if ($scope.currentLogger) {
|
||||
$scope.currentLogger.showOptions = false;
|
||||
}
|
||||
logger.showOptions = true;
|
||||
$scope.currentLogger = logger;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setLevel = function(logger, newLevel) {
|
||||
if (!$scope.isPermitted(permissions.CONFIG_EDIT_PERM)) {
|
||||
return;
|
||||
}
|
||||
var setString = logger.name + ":" + newLevel;
|
||||
logger.showOptions = false;
|
||||
Logging.setLevel({set: setString}, function(data) {
|
||||
$scope.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
420
solr/server/solr-webapp/webapp/js/angular/controllers/login.js
vendored
Normal file
420
solr/server/solr-webapp/webapp/js/angular/controllers/login.js
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('LoginController',
|
||||
['$scope', '$routeParams', '$rootScope', '$location', '$window', 'AuthenticationService', 'Constants',
|
||||
function ($scope, $routeParams, $rootScope, $location, $window, AuthenticationService, Constants) {
|
||||
$scope.showHideMenu();
|
||||
$scope.subPath = $routeParams.route;
|
||||
$rootScope.exceptions = {};
|
||||
|
||||
// Session variables set in app.js 401 interceptor
|
||||
var wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader");
|
||||
var authScheme = sessionStorage.getItem("auth.scheme");
|
||||
if (wwwAuthHeader) {
|
||||
// Parse www-authenticate header
|
||||
var wwwHeader = wwwAuthHeader.match(/(\w+)(\s+)?(.*)/);
|
||||
authScheme = "unknown";
|
||||
var authParams = {};
|
||||
if (wwwHeader && wwwHeader.length >= 1)
|
||||
authScheme = wwwHeader[1];
|
||||
if (wwwHeader && wwwHeader.length >= 3)
|
||||
authParams = www_auth_parse_params(wwwHeader[3]);
|
||||
if (typeof authParams === 'string' || authParams instanceof String) {
|
||||
$scope.authParamsError = authParams;
|
||||
} else {
|
||||
$scope.authParamsError = undefined;
|
||||
}
|
||||
var realm = authParams['realm'];
|
||||
sessionStorage.setItem("auth.realm", realm);
|
||||
if (authScheme === 'Basic' || authScheme === 'xBasic') {
|
||||
authScheme = 'Basic';
|
||||
}
|
||||
sessionStorage.setItem("auth.scheme", authScheme);
|
||||
}
|
||||
|
||||
var supportedSchemes = ['Basic', 'Bearer', 'Negotiate', 'Certificate'];
|
||||
$scope.authSchemeSupported = supportedSchemes.includes(authScheme);
|
||||
|
||||
if (authScheme === 'Bearer') {
|
||||
// Check for OpenId redirect response
|
||||
var errorText = "";
|
||||
$scope.isCallback = false;
|
||||
if ($scope.subPath === 'callback') {
|
||||
$scope.isCallback = true;
|
||||
var hash = $location.hash();
|
||||
var hp = AuthenticationService.decodeHashParams(hash);
|
||||
var expectedState = sessionStorage.getItem("auth.stateRandom") + "_" + sessionStorage.getItem("auth.location");
|
||||
sessionStorage.setItem("auth.state", "error");
|
||||
$scope.authData = AuthenticationService.getAuthDataHeader();
|
||||
if (!validateState(hp['state'], expectedState)) {
|
||||
$scope.error = "Problems with OpenID callback";
|
||||
$scope.errorDescription = errorText;
|
||||
$scope.http401 = "true";
|
||||
sessionStorage.setItem("auth.state", "error");
|
||||
}
|
||||
else {
|
||||
var flow = $scope.authData ? $scope.authData['authorization_flow'] : undefined;
|
||||
console.log("Callback: authorization_flow : " +flow);
|
||||
var isCodePKCE = flow == 'code_pkce';
|
||||
if (isCodePKCE) {
|
||||
// code flow with PKCE
|
||||
var code = hp['code'];
|
||||
var tokenEndpoint = $scope.authData['tokenEndpoint'];
|
||||
// concurrent Solr API calls will trigger 401 and erase session's "auth.realm" in app.js
|
||||
// save it before it's erased
|
||||
var authRealm = sessionStorage.getItem("auth.realm");
|
||||
|
||||
var data = {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': $window.location.href.split('#')[0],
|
||||
'scope': "openid " + $scope.authData['scope'],
|
||||
'code_verifier': sessionStorage.getItem('codeVerifier'),
|
||||
"client_id": $scope.authData['client_id']
|
||||
};
|
||||
|
||||
console.debug(`Callback. Got code: ${code} \nCalling token endpoint:: ${tokenEndpoint} `);
|
||||
AuthenticationService.getOAuthTokens(tokenEndpoint, data).then(function(response) {
|
||||
var accessToken = response.access_token;
|
||||
var idToken = response.id_token;
|
||||
var tokenType = response.access_type;
|
||||
sessionStorage.setItem("auth.realm", authRealm);
|
||||
processTokensResponse(accessToken, idToken, tokenType, expectedState, hp);
|
||||
}).catch(function (error) {
|
||||
errorText += "Error calling token endpoint. ";
|
||||
$scope.error = "Problems with OpenID callback";
|
||||
$scope.errorDescription = errorText;
|
||||
$scope.http401 = "true";
|
||||
sessionStorage.setItem("auth.state", "error");
|
||||
if (error && error.data) {
|
||||
console.error("Error getting tokens: " + JSON.stringify(error.data));
|
||||
} else {
|
||||
console.error("Error getting tokens: " + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// implicit flow
|
||||
processTokensResponse(hp['access_token'], hp['id_token'], hp['token_type'], expectedState, hp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateState(state, expectedState) {
|
||||
if (state !== expectedState) {
|
||||
$scope.error = "Problem with auth callback";
|
||||
console.error("Expected state param " + expectedState + " but got " + state);
|
||||
errorText += "Invalid values in state parameter. ";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function processTokensResponse(accessToken, idToken, tokenType, expectedState, hp) {
|
||||
if (accessToken && hp['state']) {
|
||||
// Validate token type.
|
||||
if (!tokenType) {
|
||||
//Assume the type is 'bearer' if it's not returned. Most IdProviders support 'bearer' by default but don't always return the type.
|
||||
tokenType = "bearer";
|
||||
}
|
||||
else if(tokenType.toLowerCase() !== "bearer") {
|
||||
console.error("Expected token_type param 'bearer', but got " + tokenType);
|
||||
errorText += "Invalid values in token_type parameter. ";
|
||||
}
|
||||
// Unpack ID token and validate nonce, get username
|
||||
if (idToken) {
|
||||
var idTokenArray = idToken.split(".");
|
||||
if (idTokenArray.length === 3) {
|
||||
var payload = AuthenticationService.decodeJwtPart(idTokenArray[1]);
|
||||
if (!payload['nonce'] || payload['nonce'] !== sessionStorage.getItem("auth.nonce")) {
|
||||
errorText += "Invalid 'nonce' value, possible attack detected. Please log in again. ";
|
||||
}
|
||||
|
||||
if (errorText === "") {
|
||||
sessionStorage.setItem("auth.username", payload['sub']);
|
||||
sessionStorage.setItem("auth.header", "Bearer " + accessToken);
|
||||
sessionStorage.removeItem("auth.statusText");
|
||||
sessionStorage.removeItem("auth.stateRandom");
|
||||
sessionStorage.removeItem("auth.wwwAuthHeader");
|
||||
console.log("User " + payload['sub'] + " is logged in");
|
||||
var redirectTo = sessionStorage.getItem("auth.location");
|
||||
console.log("Redirecting to stored location " + redirectTo);
|
||||
sessionStorage.setItem("auth.state", "authenticated");
|
||||
sessionStorage.removeItem("http401");
|
||||
sessionStorage.setItem("auth.scheme", "Bearer");
|
||||
$location.path(redirectTo).hash("");
|
||||
}
|
||||
} else {
|
||||
console.error("Expected JWT compact id_token param but got " + idTokenArray);
|
||||
errorText += "Invalid values in id_token parameter. ";
|
||||
}
|
||||
} else {
|
||||
console.error("Callback was missing the id_token parameter, could not validate nonce.");
|
||||
errorText += "Callback was missing the id_token parameter, could not validate nonce. ";
|
||||
}
|
||||
if (accessToken.split(".").length !== 3) {
|
||||
console.error("Expected JWT compact access_token param but got " + accessToken);
|
||||
errorText += "Invalid values in access_token parameter. ";
|
||||
}
|
||||
if (errorText !== "") {
|
||||
$scope.error = "Problems with OpenID callback";
|
||||
$scope.errorDescription = errorText;
|
||||
$scope.http401 = "true";
|
||||
}
|
||||
// End callback processing
|
||||
} else if (hp['error']) {
|
||||
// The callback had errors
|
||||
console.error("Error received from idp: " + hp['error']);
|
||||
var errorDescriptions = {};
|
||||
errorDescriptions['invalid_request'] = "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.";
|
||||
errorDescriptions['unauthorized_client'] = "The client is not authorized to request an access token using this method.";
|
||||
errorDescriptions['access_denied'] = "The resource owner or authorization server denied the request.";
|
||||
errorDescriptions['unsupported_response_type'] = "The authorization server does not support obtaining an access token using this method.";
|
||||
errorDescriptions['invalid_scope'] = "The requested scope is invalid, unknown, or malformed.";
|
||||
errorDescriptions['server_error'] = "The authorization server encountered an unexpected condition that prevented it from fulfilling the request.";
|
||||
errorDescriptions['temporarily_unavailable'] = "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.";
|
||||
$scope.error = "Callback from Id Provider contained error. ";
|
||||
if (hp['error_description']) {
|
||||
$scope.errorDescription = decodeURIComponent(hp['error_description']);
|
||||
} else {
|
||||
$scope.errorDescription = errorDescriptions[hp['error']];
|
||||
}
|
||||
if (hp['error_uri']) {
|
||||
$scope.errorDescription += " More information at " + hp['error_uri'] + ". ";
|
||||
}
|
||||
if (hp['state'] !== expectedState) {
|
||||
$scope.errorDescription += "The state parameter returned from ID Provider did not match the one we sent.";
|
||||
}
|
||||
sessionStorage.setItem("auth.state", "error");
|
||||
}
|
||||
else{
|
||||
console.error(`Invalid data received from idp: accessToken: ${accessToken},
|
||||
idToken: ${idToken}, state: ${hp['state']}`);
|
||||
errorText += "Invalid data received from the OpenID provider. ";
|
||||
$scope.http401 = "true";
|
||||
$scope.error = "Problems with OpenID callback.";
|
||||
$scope.errorDescription = errorText;
|
||||
sessionStorage.setItem("auth.state", "error");
|
||||
}
|
||||
}
|
||||
|
||||
if (errorText === "" && !$scope.error && authParams) {
|
||||
$scope.error = authParams['error'];
|
||||
$scope.errorDescription = authParams['error_description'];
|
||||
$scope.authData = AuthenticationService.getAuthDataHeader();
|
||||
}
|
||||
|
||||
$scope.authScheme = sessionStorage.getItem("auth.scheme");
|
||||
$scope.authRealm = sessionStorage.getItem("auth.realm");
|
||||
$scope.wwwAuthHeader = sessionStorage.getItem("auth.wwwAuthHeader");
|
||||
$scope.statusText = sessionStorage.getItem("auth.statusText");
|
||||
$scope.authLocation = sessionStorage.getItem("auth.location");
|
||||
$scope.authLoggedinUser = sessionStorage.getItem("auth.username");
|
||||
$scope.authHeader = sessionStorage.getItem("auth.header");
|
||||
|
||||
$scope.login = function () {
|
||||
AuthenticationService.SetCredentials($scope.username, $scope.password);
|
||||
$location.path($scope.authLocation); // Redirect to the location that caused the login prompt
|
||||
};
|
||||
|
||||
$scope.logout = function() {
|
||||
// reset login status
|
||||
AuthenticationService.ClearCredentials();
|
||||
$location.path("/");
|
||||
};
|
||||
|
||||
$scope.jwtLogin = async function () {
|
||||
var stateRandom = Math.random().toString(36).substr(2);
|
||||
sessionStorage.setItem("auth.stateRandom", stateRandom);
|
||||
var authState = stateRandom + "_" + sessionStorage.getItem("auth.location");
|
||||
var authNonce = Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2);
|
||||
sessionStorage.setItem("auth.nonce", authNonce);
|
||||
var authData = AuthenticationService.getAuthDataHeader();
|
||||
var flow = authData ? authData['authorization_flow'] : "implicit";
|
||||
console.log("jwtLogin flow: "+ flow);
|
||||
var isCodePKCE = flow == 'code_pkce';
|
||||
|
||||
var params = {};
|
||||
if (isCodePKCE) {
|
||||
console.debug("Login with 'Code PKCE' flow");
|
||||
var codeVerifier = AuthenticationService.generateCodeVerifier();
|
||||
var code_challenge = await AuthenticationService.generateCodeChallengeFromVerifier(codeVerifier);
|
||||
var codeChallengeMethod = AuthenticationService.getCodeChallengeMethod();
|
||||
sessionStorage.setItem('codeVerifier', codeVerifier);
|
||||
params = {
|
||||
"response_type": "code",
|
||||
"client_id": $scope.authData['client_id'],
|
||||
"redirect_uri": $window.location.href.split('#')[0],
|
||||
"scope": "openid " + $scope.authData['scope'],
|
||||
"state": authState,
|
||||
"nonce": authNonce,
|
||||
"response_mode": "fragment",
|
||||
"code_challenge": code_challenge,
|
||||
"code_challenge_method": codeChallengeMethod
|
||||
};
|
||||
}
|
||||
else {
|
||||
console.debug("Login with 'Implicit' flow");
|
||||
params = {
|
||||
"response_type": "id_token token",
|
||||
"client_id": $scope.authData['client_id'],
|
||||
"redirect_uri": $window.location.href.split('#')[0],
|
||||
"scope": "openid " + $scope.authData['scope'],
|
||||
"state": authState,
|
||||
"nonce": authNonce,
|
||||
"response_mode": 'fragment',
|
||||
"grant_type": 'implicit'
|
||||
};
|
||||
}
|
||||
|
||||
var endpointBaseUrl = $scope.authData['authorizationEndpoint'];
|
||||
var loc = endpointBaseUrl + "?" + paramsToString(params);
|
||||
console.log("Redirecting to " + loc);
|
||||
sessionStorage.setItem("auth.state", "expectCallback");
|
||||
$window.location.href = loc;
|
||||
|
||||
function paramsToString(params) {
|
||||
var arr = [];
|
||||
for (var p in params) {
|
||||
if( params.hasOwnProperty(p) ) {
|
||||
arr.push(p + "=" + encodeURIComponent(params[p]));
|
||||
}
|
||||
}
|
||||
return arr.join("&");
|
||||
}
|
||||
};
|
||||
|
||||
$scope.jwtIsLoginNode = function() {
|
||||
var redirect = $scope.authData ? $scope.authData['redirect_uris'] : undefined;
|
||||
if (redirect && Array.isArray(redirect) && redirect.length > 0) {
|
||||
var isLoginNode = false;
|
||||
redirect.forEach(function(uri) { // Check that current node URL is among the configured callback URIs
|
||||
if ($window.location.href.startsWith(uri)) isLoginNode = true;
|
||||
});
|
||||
return isLoginNode;
|
||||
} else {
|
||||
return true; // no redirect UIRs configured, all nodes are potential login nodes
|
||||
}
|
||||
};
|
||||
|
||||
$scope.jwtFindLoginNode = function() {
|
||||
var redirect = $scope.authData ? $scope.authData['redirect_uris'] : undefined;
|
||||
if (redirect && Array.isArray(redirect) && redirect.length > 0) {
|
||||
var loginNode = redirect[0];
|
||||
redirect.forEach(function(uri) { // if current node is in list, return its callback uri
|
||||
if ($window.location.href.startsWith(uri)) loginNode = uri;
|
||||
});
|
||||
return loginNode;
|
||||
} else {
|
||||
return $window.location.href.split('#')[0]; // Return base url of current URL as the url to use
|
||||
}
|
||||
};
|
||||
|
||||
// Redirect to login node if this is not a valid one
|
||||
$scope.jwtGotoLoginNode = function() {
|
||||
if (!$scope.jwtIsLoginNode()) {
|
||||
$window.location.href = $scope.jwtFindLoginNode();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.jwtLogout = function() {
|
||||
// reset login status
|
||||
AuthenticationService.ClearCredentials();
|
||||
$location.path("/");
|
||||
};
|
||||
|
||||
$scope.isLoggedIn = function() {
|
||||
return (sessionStorage.getItem("auth.username") !== null);
|
||||
};
|
||||
}]);
|
||||
|
||||
// This function is copied and adapted from MIT-licensed https://github.com/randymized/www-authenticate/blob/master/lib/parsers.js
|
||||
www_auth_parse_params= function (header) {
|
||||
// This parser will definitely fail if there is more than one challenge
|
||||
var params = {};
|
||||
var tok, last_tok, _i, _len, key, value;
|
||||
var state= 0; //0: token,
|
||||
var m= header.split(/([",=])/);
|
||||
for (_i = 0, _len = m.length; _i < _len; _i++) {
|
||||
last_tok= tok;
|
||||
tok = m[_i];
|
||||
if (!tok.length) continue;
|
||||
switch (state) {
|
||||
case 0: // token
|
||||
key= tok.trim();
|
||||
state= 1; // expect equals
|
||||
continue;
|
||||
case 1: // expect equals
|
||||
if ('=' != tok) return 'Equal sign was expected after '+key;
|
||||
state= 2;
|
||||
continue;
|
||||
case 2: // expect value
|
||||
if ('"' == tok) {
|
||||
value= '';
|
||||
state= 3; // expect quoted
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
params[key]= value= tok.trim();
|
||||
state= 9; // expect comma or end
|
||||
continue;
|
||||
}
|
||||
case 3: // handling quoted string
|
||||
if ('"' == tok) {
|
||||
state= 8; // end quoted
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
value+= tok;
|
||||
state= 3; // continue accumulating quoted string
|
||||
continue;
|
||||
}
|
||||
case 8: // end quote encountered
|
||||
if ('"' == tok) {
|
||||
// double quoted
|
||||
value+= '"';
|
||||
state= 3; // back to quoted string
|
||||
continue;
|
||||
}
|
||||
if (',' == tok) {
|
||||
params[key]= value;
|
||||
state= 0;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return 'Unexpected token ('+tok+') after '+value+'"';
|
||||
}
|
||||
continue;
|
||||
case 9: // expect commma
|
||||
if (',' != tok) return 'Comma expected after '+value;
|
||||
state= 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (state) { // terminal state
|
||||
case 0: // Empty or ignoring terminal comma
|
||||
case 9: // Expecting comma or end of header
|
||||
return params;
|
||||
case 8: // Last token was end quote
|
||||
params[key]= value;
|
||||
return params;
|
||||
default:
|
||||
return 'Unexpected end of www-authenticate value.';
|
||||
}
|
||||
};
|
||||
158
solr/server/solr-webapp/webapp/js/angular/controllers/paramsets.js
vendored
Normal file
158
solr/server/solr-webapp/webapp/js/angular/controllers/paramsets.js
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
//helper for formatting JSON and others
|
||||
|
||||
solrAdminApp.controller('ParamSetsController',
|
||||
function($scope, $location, $routeParams, ParamSet, Constants) {
|
||||
|
||||
$scope.paramsetList = [];
|
||||
|
||||
$scope.resetMenu("paramsets", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.sampleAPICommand = {
|
||||
"set": {
|
||||
"myQueries": {
|
||||
"defType": "edismax",
|
||||
"rows": "5",
|
||||
"df": "text_all"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.selectParamset = function() {
|
||||
$location.search("paramset", $scope.name);
|
||||
$scope.getParamset($scope.name);
|
||||
}
|
||||
|
||||
$scope.getParamset = function (paramset) {
|
||||
$scope.refresh();
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
params.name = paramset;
|
||||
|
||||
ParamSet.get(params, callback, failure);
|
||||
|
||||
///////
|
||||
|
||||
function callback(success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
var apiPayload = {
|
||||
"set": success.response.params
|
||||
};
|
||||
// remove json key that is defined as "", it can't be submitted via the API.
|
||||
var paramsetName = Object.keys(apiPayload.set)[0];
|
||||
delete apiPayload.set[paramsetName][""]
|
||||
|
||||
$scope.paramsetContent = JSON.stringify(apiPayload, null, ' ');
|
||||
}
|
||||
|
||||
function failure (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$scope.getParamsets = function () {
|
||||
$scope.refresh();
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
|
||||
ParamSet.get(params, callback, failure);
|
||||
|
||||
///////
|
||||
|
||||
function callback(success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
$scope.paramsetList = success.response.params ? Object.keys(success.response.params) : [];
|
||||
}
|
||||
|
||||
function failure (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.getParamsets();
|
||||
if ($routeParams.paramset){
|
||||
$scope.name = $routeParams.paramset;
|
||||
$scope.getParamset($routeParams.paramset);
|
||||
}
|
||||
|
||||
$scope.refresh = function () {
|
||||
$scope.paramsetContent = "";
|
||||
$scope.placeholder = JSON.stringify($scope.sampleAPICommand, null, ' ');
|
||||
};
|
||||
$scope.refresh();
|
||||
|
||||
$scope.submit = function () {
|
||||
var params = {};
|
||||
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
|
||||
ParamSet.submit(params, $scope.paramsetContent, callback, failure);
|
||||
|
||||
///////
|
||||
function callback(success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
$scope.name = null;
|
||||
$scope.getParamsets();
|
||||
}
|
||||
function failure (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.deleteParamset = function () {
|
||||
var params = {};
|
||||
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
params.name = $scope.name;
|
||||
|
||||
var apiPayload = {
|
||||
"delete": [$scope.name]
|
||||
};
|
||||
|
||||
ParamSet.submit(params, apiPayload, callback, failure);
|
||||
|
||||
///////
|
||||
function callback(success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.response = JSON.stringify(success, null, ' ');
|
||||
$scope.getParamsets();
|
||||
}
|
||||
function failure (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
167
solr/server/solr-webapp/webapp/js/angular/controllers/plugins.js
vendored
Normal file
167
solr/server/solr-webapp/webapp/js/angular/controllers/plugins.js
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('PluginsController',
|
||||
function($scope, $rootScope, $routeParams, $location, Mbeans, Constants) {
|
||||
$scope.resetMenu("plugins", Constants.IS_CORE_PAGE);
|
||||
|
||||
if ($routeParams.legacytype) {
|
||||
// support legacy URLs. Angular cannot change #path without reloading controller
|
||||
$location.path("/"+$routeParams.core+"/plugins");
|
||||
$location.search("type", $routeParams.legacytype);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.refresh = function() {
|
||||
Mbeans.stats({core: $routeParams.core}, function (data) {
|
||||
var type = $location.search().type;
|
||||
$scope.types = getPluginTypes(data, type);
|
||||
$scope.type = getSelectedType($scope.types, type);
|
||||
|
||||
if ($scope.type && $routeParams.entry) {
|
||||
$scope.plugins = $routeParams.entry.split(",");
|
||||
openPlugins($scope.type, $scope.plugins);
|
||||
} else {
|
||||
$scope.plugins = [];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.selectPluginType = function(type) {
|
||||
$location.search({entry:null, type: type.lower});
|
||||
$scope.type = type;
|
||||
};
|
||||
|
||||
$scope.selectPlugin = function(plugin) {
|
||||
plugin.open = !plugin.open;
|
||||
|
||||
if (plugin.open) {
|
||||
$scope.plugins.push(plugin.name);
|
||||
} else {
|
||||
$scope.plugins.splice($scope.plugins.indexOf(plugin.name), 1);
|
||||
}
|
||||
|
||||
if ($scope.plugins.length==0) {
|
||||
$location.search("entry", null);
|
||||
} else {
|
||||
$location.search("entry", $scope.plugins.join(','));
|
||||
}
|
||||
}
|
||||
|
||||
$scope.startRecording = function() {
|
||||
$scope.isRecording = true;
|
||||
Mbeans.reference({core: $routeParams.core}, function(data) {
|
||||
$scope.reference = data.reference;
|
||||
console.log($scope.reference);
|
||||
})
|
||||
}
|
||||
|
||||
$scope.stopRecording = function() {
|
||||
$scope.isRecording = false;
|
||||
console.log($scope.reference);
|
||||
Mbeans.delta({core: $routeParams.core}, $scope.reference, function(data) {
|
||||
parseDelta($scope.types, data);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var getPluginTypes = function(data, selected) {
|
||||
var keys = [];
|
||||
var mbeans = data["solr-mbeans"];
|
||||
for (var i=0; i<mbeans.length; i+=2) {
|
||||
var key = mbeans[i];
|
||||
var lower = key.toLowerCase();
|
||||
var plugins = getPlugins(mbeans[i+1]);
|
||||
if (plugins.length == 0) continue;
|
||||
keys.push({name: key,
|
||||
selected: lower == selected,
|
||||
changes: 0,
|
||||
lower: lower,
|
||||
plugins: plugins
|
||||
});
|
||||
}
|
||||
keys.sort(function(a,b) {return a.name > b.name});
|
||||
return keys;
|
||||
};
|
||||
|
||||
var getPlugins = function(data) {
|
||||
var plugins = [];
|
||||
for (var key in data) {
|
||||
var pluginProperties = data[key];
|
||||
var stats = pluginProperties.stats;
|
||||
delete pluginProperties.stats;
|
||||
for (var stat in stats) {
|
||||
// add breaking space after a bracket or @ to handle wrap long lines:
|
||||
stats[stat] = new String(stats[stat]).replace( /([\(@])/g, '$1​');
|
||||
}
|
||||
plugin = {name: key, changed: false, stats: stats, open:false};
|
||||
plugin.properties = pluginProperties;
|
||||
plugins.push(plugin);
|
||||
}
|
||||
plugins.sort(function(a,b) {return a.name > b.name});
|
||||
return plugins;
|
||||
};
|
||||
|
||||
var getSelectedType = function(types, selected) {
|
||||
if (selected) {
|
||||
for (var i in types) {
|
||||
if (types[i].lower == selected) {
|
||||
return types[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var parseDelta = function(types, data) {
|
||||
|
||||
var getByName = function(list, name) {
|
||||
for (var i in list) {
|
||||
if (list[i].name == name) return list[i];
|
||||
}
|
||||
}
|
||||
|
||||
var mbeans = data["solr-mbeans"]
|
||||
for (var i=0; i<mbeans.length; i+=2) {
|
||||
var typeName = mbeans[i];
|
||||
var type = getByName(types, typeName);
|
||||
var plugins = mbeans[i+1];
|
||||
for (var key in plugins) {
|
||||
var changedPlugin = plugins[key];
|
||||
if (changedPlugin._changed_) {
|
||||
var plugin = getByName(type.plugins, key);
|
||||
var stats = changedPlugin.stats;
|
||||
delete changedPlugin.stats;
|
||||
plugin.properties = changedPlugin;
|
||||
for (var stat in stats) {
|
||||
// add breaking space after a bracket or @ to handle wrap long lines:
|
||||
plugin.stats[stat] = new String(stats[stat]).replace( /([\(@])/g, '$1​');
|
||||
}
|
||||
plugin.changed = true;
|
||||
type.changes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var openPlugins = function(type, selected) {
|
||||
for (var i in type.plugins) {
|
||||
var plugin = type.plugins[i];
|
||||
plugin.open = selected.indexOf(plugin.name)>=0;
|
||||
}
|
||||
}
|
||||
308
solr/server/solr-webapp/webapp/js/angular/controllers/query.js
vendored
Normal file
308
solr/server/solr-webapp/webapp/js/angular/controllers/query.js
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('QueryController',
|
||||
function($scope, $route, $routeParams, $location, Query, Constants, ParamSet){
|
||||
$scope.resetMenu("query", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope._models = [];
|
||||
$scope.filters = [{fq:""}];
|
||||
$scope.rawParams = [{rawParam:""}];
|
||||
$scope.val = {};
|
||||
$scope.val['q'] = "*:*";
|
||||
$scope.val['q.op'] = "OR";
|
||||
$scope.val['defType'] = "";
|
||||
$scope.val['indent'] = true;
|
||||
$scope.useParams = [];
|
||||
|
||||
getParamsets();
|
||||
|
||||
function getParamsets() {
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.wt = "json";
|
||||
|
||||
ParamSet.get(params, callback, failure);
|
||||
|
||||
///////
|
||||
|
||||
function callback(success) {
|
||||
$scope.responseStatus = "success";
|
||||
delete success.$promise;
|
||||
delete success.$resolved;
|
||||
$scope.paramsetList = success.response.params ? Object.keys(success.response.params) : [];
|
||||
}
|
||||
|
||||
function failure (failure) {
|
||||
$scope.responseStatus = failure;
|
||||
}
|
||||
}
|
||||
|
||||
// get list of ng-models that have a form element
|
||||
function setModels(argTagName){
|
||||
var fields = document.getElementsByTagName(argTagName);
|
||||
for( var i = 0, iLen = fields.length; i<iLen; i++ ){
|
||||
var model = fields[i].getAttribute("ng-model");
|
||||
if( model ){
|
||||
$scope._models.push({modelName: model, element: fields[i]});
|
||||
}
|
||||
}
|
||||
}
|
||||
function setUrlParams(){
|
||||
var urlParams = $location.search();
|
||||
for( var p in urlParams ){
|
||||
if( !urlParams.hasOwnProperty(p) ){
|
||||
continue;
|
||||
}
|
||||
// filters and rawParams are handled specially because of possible multiple values
|
||||
if( p === "fq" ) {
|
||||
addFilters(urlParams[p]);
|
||||
} else {
|
||||
setParam(p, urlParams[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function setParam(argKey, argValue, argProperty){
|
||||
if( argProperty ){
|
||||
$scope[argProperty][argKey] = argValue;
|
||||
} else if ( $scope._models.map(function(field){return field.modelName}).indexOf("val['" + argKey + "']") > -1 ) {
|
||||
// parameters stored in "val" will be used in both links (admin link and REST-request)
|
||||
var index = $scope._models.map(function(field){return field.modelName}).indexOf("val['" + argKey + "']");
|
||||
var field = $scope._models[index].element;
|
||||
if( argValue === "true" || argValue === "false"){
|
||||
// use real booleans
|
||||
argValue = argValue === "true";
|
||||
} else if( field.tagName.toUpperCase() === "INPUT" && field.type === "checkbox" && (argValue === "on" || argValue === "off") ){
|
||||
argValue = argValue === "on";
|
||||
}
|
||||
$scope.val[argKey] = argValue;
|
||||
} else if( $scope._models.map(function(field){return field.modelName}).indexOf(argKey) > -1 ) {
|
||||
// parameters that will only be used to generate the admin link
|
||||
if (argKey === 'useParams'){
|
||||
$scope[argKey] = argValue.split(",")
|
||||
}
|
||||
else {
|
||||
$scope[argKey] = argValue;
|
||||
}
|
||||
} else {
|
||||
insertToRawParams(argKey, argValue);
|
||||
}
|
||||
}
|
||||
// store not processed values to be displayed in a field
|
||||
function insertToRawParams(argKey, argValue){
|
||||
if( ($scope.rawParams.length === 0) || ($scope.rawParams.length === 1 && $scope.rawParams[0].rawParam === "") ){
|
||||
$scope.rawParams = [];
|
||||
}
|
||||
if (argValue instanceof Array) {
|
||||
for (var index in argValue) {
|
||||
$scope.rawParams.push({rawParam: argKey + "=" + argValue[index]});
|
||||
}
|
||||
} else {
|
||||
$scope.rawParams.push({rawParam: argKey + "=" + argValue});
|
||||
}
|
||||
}
|
||||
function addFilters(argObject){
|
||||
if( argObject ){
|
||||
$scope.filters = [];
|
||||
if( Array.isArray(argObject) ){
|
||||
for( var i = 0, iLen = argObject.length; i<iLen; i++ ){
|
||||
$scope.filters.push({fq: argObject[i]});
|
||||
}
|
||||
} else {
|
||||
$scope.filters.push({fq: argObject});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.doQuery = function(isPageReload) {
|
||||
var params = {};
|
||||
|
||||
var set = function(key, value) {
|
||||
if (params[key]) {
|
||||
params[key].push(value);
|
||||
} else {
|
||||
params[key] = [value];
|
||||
}
|
||||
}
|
||||
var copy = function(params, query) {
|
||||
for (var key in query) {
|
||||
terms = query[key];
|
||||
// Booleans have no length property - only set them if true
|
||||
if (typeof(terms) == typeof(true) || (terms.length && terms.length > 0 && key[0]!=="$") ) {
|
||||
set(key, terms);
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove non-visible fields from the request-params
|
||||
var purgeParams = function(params, fields, bRemove){
|
||||
if( !bRemove ){
|
||||
return;
|
||||
}
|
||||
for( var i = 0, iLen = fields.length; i<iLen; i++ ){
|
||||
if( params.hasOwnProperty(fields[i]) ){
|
||||
delete params[fields[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
var getDependentFields = function(argParam){
|
||||
return Object.keys($scope.val)
|
||||
.filter(function(param){
|
||||
return param.indexOf(argParam) === 0;
|
||||
});
|
||||
}
|
||||
|
||||
var getHighlighterFieldsToPurge = function(hlMethod){
|
||||
// first, select the fieldsets which ng-show includes val['hl.method'] but not val['hl.method']==${hlMethod}
|
||||
// then, select their descendants that have ng-model
|
||||
const selector = `div.fieldset[ng-show*="val['hl.method']"]:not([ng-show*="val['hl.method']=='${hlMethod}'"])
|
||||
[ng-model]`;
|
||||
// return the field names
|
||||
return Array.from(document.querySelectorAll(selector), x => x.name);
|
||||
}
|
||||
|
||||
copy(params, $scope.val);
|
||||
purgeParams(params, ["q.alt", "qf", "mm", "pf", "ps", "qs", "tie", "bq", "bf"], $scope.val.defType !== "dismax" && $scope.val.defType !== "edismax");
|
||||
purgeParams(params, ["uf", "pf2", "pf3", "ps2", "ps3", "boost", "stopwords", "lowercaseOperators"], $scope.val.defType !== "edismax");
|
||||
purgeParams(params, getDependentFields("hl"), $scope.val.hl !== true);
|
||||
purgeParams(params, getHighlighterFieldsToPurge($scope.val["hl.method"]), true);
|
||||
purgeParams(params, getDependentFields("facet"), $scope.val.facet !== true);
|
||||
purgeParams(params, ["spatial", "pt", "sfield", "d"], $scope.val.spatial !== true);
|
||||
purgeParams(params, getDependentFields("spellcheck"), $scope.val.spellcheck !== true);
|
||||
var qt = $scope.qt ? $scope.qt : "/select";
|
||||
|
||||
for (var filter in $scope.filters) {
|
||||
copy(params, $scope.filters[filter]);
|
||||
}
|
||||
|
||||
for (var rawIndex in $scope.rawParams) {
|
||||
if ($scope.rawParams[rawIndex].rawParam) {
|
||||
var rawParam = $scope.rawParams[rawIndex].rawParam.split(/[&\n]/);
|
||||
for (var i in rawParam) {
|
||||
var param = rawParam[i];
|
||||
var equalPos = param.indexOf("=");
|
||||
if (equalPos > -1) {
|
||||
set(param.substring(0, equalPos), param.substring(equalPos+1));
|
||||
} else {
|
||||
set(param, ""); // Use empty value for params without "="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.core = $routeParams.core;
|
||||
if (qt[0] === '/') {
|
||||
params.handler = qt.substring(1);
|
||||
} else { // Support legacy style handleSelect=true configs
|
||||
params.handler = "select";
|
||||
set("qt", qt);
|
||||
}
|
||||
|
||||
// convert useParams to array to generate nice URL.
|
||||
if (!Array.isArray($scope.useParams)){
|
||||
params.useParams = $scope.useParams.split(",");
|
||||
}
|
||||
else {
|
||||
params.useParams = $scope.useParams;
|
||||
}
|
||||
|
||||
// create rest result url
|
||||
var url = Query.url(params);
|
||||
|
||||
// convert useParams back to string
|
||||
if (Array.isArray($scope.useParams)){
|
||||
params.useParams = $scope.useParams.join(",");
|
||||
}
|
||||
else {
|
||||
params.useParams = $scope.useParams;
|
||||
}
|
||||
|
||||
// create admin page url
|
||||
var adminParams = {...params};
|
||||
delete adminParams.handler;
|
||||
delete adminParams.core
|
||||
if (!Array.isArray(adminParams.useParams)){
|
||||
adminParams.useParams = adminParams.useParams.split(",");
|
||||
}
|
||||
if( $scope.qt != null ) {
|
||||
adminParams.qt = [$scope.qt];
|
||||
}
|
||||
if (isPageReload) {
|
||||
if (!Array.isArray(params.useParams)){
|
||||
params.useParams = params.useParams.split(",");
|
||||
}
|
||||
|
||||
Query.query(params, function (data) {
|
||||
$scope.lang = $scope.val['wt'];
|
||||
if (!$scope.lang || $scope.lang === '') {
|
||||
$scope.lang = "json";
|
||||
}
|
||||
$scope.response = data;
|
||||
// Use relative URL to make it also work through proxies that may have a different host/port/context
|
||||
$scope.url = url;
|
||||
$scope.hostPortContext = $location.absUrl().substr(0, $location.absUrl().indexOf("#")); // For display only
|
||||
});
|
||||
} else {
|
||||
var previousUrl = $location.$$url;
|
||||
for( key in $location.search() ){
|
||||
$location.search(key, null);
|
||||
}
|
||||
for( var key in adminParams ){
|
||||
if( Array.isArray(adminParams[key]) && adminParams[key].length === 1 ){
|
||||
adminParams[key] = adminParams[key][0];
|
||||
}
|
||||
if( typeof adminParams[key] === typeof true ){
|
||||
adminParams[key] = adminParams[key].toString();
|
||||
}
|
||||
$location.search(key, adminParams[key]);
|
||||
}
|
||||
var currentUrl = $location.$$url;
|
||||
if (previousUrl === currentUrl) { //if the query send with same parameters the query should be executed
|
||||
$route.reload();
|
||||
}
|
||||
}
|
||||
};
|
||||
setModels("input");
|
||||
setModels("textarea");
|
||||
setModels("select");
|
||||
setUrlParams();
|
||||
|
||||
if ($location.search().q) {
|
||||
$scope.doQuery(true);
|
||||
}
|
||||
$scope.removeFilter = function(index) {
|
||||
if ($scope.filters.length === 1) {
|
||||
$scope.filters = [{fq: ""}];
|
||||
} else {
|
||||
$scope.filters.splice(index, 1);
|
||||
}
|
||||
};
|
||||
$scope.addFilter = function(index) {
|
||||
$scope.filters.splice(index+1, 0, {fq:""});
|
||||
};
|
||||
$scope.removeRawParam = function (index) {
|
||||
if ($scope.rawParams.length === 1) {
|
||||
$scope.rawParams = [{rawParam: ""}];
|
||||
} else {
|
||||
$scope.rawParams.splice(index, 1);
|
||||
}
|
||||
};
|
||||
$scope.addRawParam = function (index) {
|
||||
$scope.rawParams.splice(index+1, 0, {rawParam:""});
|
||||
};
|
||||
}
|
||||
);
|
||||
235
solr/server/solr-webapp/webapp/js/angular/controllers/replication.js
vendored
Normal file
235
solr/server/solr-webapp/webapp/js/angular/controllers/replication.js
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('ReplicationController',
|
||||
function($scope, $rootScope, $routeParams, $interval, $timeout, Replication, Constants) {
|
||||
$scope.resetMenu("replication", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.iterationCount = 1;
|
||||
|
||||
$scope.refresh = function() {
|
||||
Replication.details({core:$routeParams.core}, function(response) {
|
||||
var timeout;
|
||||
var interval;
|
||||
if ($scope.interval) $interval.cancel($scope.interval);
|
||||
$scope.isFollower = (response.details.isFollower === 'true');
|
||||
if ($scope.isFollower) {
|
||||
$scope.progress = getProgressDetails(response.details.follower);
|
||||
$scope.iterations = getIterations(response.details.follower);
|
||||
$scope.versions = getFollowerVersions(response.details);
|
||||
$scope.settings = getFollowerSettings(response.details);
|
||||
if ($scope.settings.isReplicating) {
|
||||
timeout = $timeout($scope.refresh, 1000);
|
||||
} else if(!$scope.settings.isPollingDisabled && $scope.settings.pollInterval) {
|
||||
interval = $scope.interval = $interval(function() {
|
||||
$scope.settings.tick--;
|
||||
}, 1000, $scope.settings.tick);
|
||||
timeout = $timeout($scope.refresh, 1000*(1+$scope.settings.tick));
|
||||
}
|
||||
} else {
|
||||
$scope.versions = getLeaderVersions(response.details);
|
||||
}
|
||||
$scope.leader = getLeaderSettings(response.details, $scope.isFollower);
|
||||
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
if (interval) $interval.cancel(interval);
|
||||
if (timeout) $timeout.cancel(timeout);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.execute = function(command) {
|
||||
Replication.command({core:$routeParams.core, command:command}, function(data){$scope.refresh()});
|
||||
}
|
||||
|
||||
$scope.showIterations = function() { $scope.iterationCount = 100000}; // limitTo should accept undefined, but doesn't work.
|
||||
$scope.hideIterations = function() { $scope.iterationCount = 1};
|
||||
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var getProgressDetails = function(progress) {
|
||||
|
||||
progress.timeRemaining = parseSeconds(progress.timeRemaining);
|
||||
progress.totalPercent = parseInt(progress.totalPercent);
|
||||
if (progress.totalPercent === 0) {
|
||||
progress.totalPercentWidth = "1px";
|
||||
} else {
|
||||
progress.totalPercentWidth = progress.totalPercent + "%";
|
||||
}
|
||||
progress.currentFileSizePercent = parseInt(progress.currentFileSizePercent);
|
||||
|
||||
if (!progress.indexReplicatedAtList) {
|
||||
progress.indexReplicatedAtList = [];
|
||||
}
|
||||
|
||||
if (!progress.replicationFailedAtList) {
|
||||
progress.replicationFailedAtList = [];
|
||||
}
|
||||
return progress;
|
||||
};
|
||||
|
||||
var getIterations = function(follower) {
|
||||
|
||||
var iterations = [];
|
||||
|
||||
var find = function(list, date) {
|
||||
return list.filter(function(e) {return e.date == date});
|
||||
};
|
||||
|
||||
for (var i in follower.indexReplicatedAtList) {
|
||||
var date = follower.indexReplicatedAtList[i];
|
||||
var iteration = {date:date, status:"replicated", latest: false};
|
||||
if (date == follower.indexReplicatedAt) {
|
||||
iteration.latest = true;
|
||||
}
|
||||
iterations.push(iteration);
|
||||
}
|
||||
|
||||
for (var i in follower.replicationFailedAtList) {
|
||||
var failedDate = follower.replicationFailedAtList[i];
|
||||
var matchingIterations = find(iterations, failedDate);
|
||||
if (matchingIterations[0]) {
|
||||
iteration = matchingIterations[0];
|
||||
iteration.status = "failed";
|
||||
} else {
|
||||
iteration = {date: failedDate, status:"failed", latest:false};
|
||||
iterations.push(iteration);
|
||||
}
|
||||
if (failedDate == follower.replicationFailedAt) {
|
||||
iteration.latest = true;
|
||||
}
|
||||
}
|
||||
iterations.sort(function(a,b){ return a.date> b.date;}).reverse();
|
||||
return iterations;
|
||||
};
|
||||
|
||||
var getLeaderVersions = function(data) {
|
||||
versions = {leaderSearch:{}, leader:{}};
|
||||
|
||||
versions.leaderSearch.version = data.indexVersion;
|
||||
versions.leaderSearch.generation = data.generation;
|
||||
versions.leaderSearch.size = data.indexSize;
|
||||
|
||||
versions.leader.version = data.leader.replicableVersion || '-';
|
||||
versions.leader.generation = data.leader.replicableGeneration || '-';
|
||||
versions.leader.size = '-';
|
||||
|
||||
return versions;
|
||||
};
|
||||
|
||||
var getFollowerVersions = function(data) {
|
||||
versions = {leaderSearch: {}, leader: {}, follower: {}};
|
||||
|
||||
versions.follower.version = data.indexVersion;
|
||||
versions.follower.generation = data.generation;
|
||||
versions.follower.size = data.indexSize;
|
||||
|
||||
versions.leader.version = data.follower.leaderDetails.replicableVersion || '-';
|
||||
versions.leader.generation = data.follower.leaderDetails.replicableGeneration || '-';
|
||||
versions.leader.size = '-';
|
||||
|
||||
versions.leaderSearch.version = data.follower.leaderDetails.indexVersion;
|
||||
versions.leaderSearch.generation = data.follower.leaderDetails.generation;
|
||||
versions.leaderSearch.size = data.follower.leaderDetails.indexSize;
|
||||
|
||||
versions.changedVersion = data.indexVersion !== data.follower.leaderDetails.indexVersion;
|
||||
versions.changedGeneration = data.generation !== data.follower.leaderDetails.generation;
|
||||
|
||||
return versions;
|
||||
};
|
||||
|
||||
var parseDateToEpoch = function(date) {
|
||||
// ["Sat Mar 03 11:00:00 CET 2012", "Sat", "Mar", "03", "11:00:00", "CET", "2012"]
|
||||
var parts = date.match( /^(\w+)\s+(\w+)\s+(\d+)\s+(\d+\:\d+\:\d+)\s+(\w+)\s+(\d+)$/ );
|
||||
|
||||
// "Sat Mar 03 2012 10:37:33"
|
||||
var d = new Date( parts[1] + ' ' + parts[2] + ' ' + parts[3] + ' ' + parts[6] + ' ' + parts[4] );
|
||||
return d.getTime();
|
||||
}
|
||||
|
||||
var parseSeconds = function(time) {
|
||||
var seconds = 0;
|
||||
var arr = new String(time || '').split('.');
|
||||
var parts = arr[0].split(':').reverse();
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
seconds += ( parseInt(parts[i], 10) || 0 ) * Math.pow(60, i);
|
||||
}
|
||||
|
||||
if (arr[1] && 5 <= parseInt(arr[1][0], 10)) {
|
||||
seconds++; // treat more or equal than .5 as additional second
|
||||
|
||||
}
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
var getFollowerSettings = function(data) {
|
||||
var settings = {};
|
||||
settings.leaderUrl = data.follower.leaderUrl;
|
||||
settings.isPollingDisabled = data.follower.isPollingDisabled == 'true';
|
||||
settings.pollInterval = data.follower.pollInterval;
|
||||
settings.isReplicating = data.follower.isReplicating == 'true';
|
||||
settings.nextExecutionAt = data.follower.nextExecutionAt;
|
||||
|
||||
if(settings.isReplicating) {
|
||||
settings.isApprox = true;
|
||||
settings.tick = parseSeconds(settings.pollInterval);
|
||||
} else if (!settings.isPollingDisabled && settings.pollInterval) {
|
||||
if( settings.nextExecutionAt ) {
|
||||
settings.nextExecutionAtEpoch = parseDateToEpoch(settings.nextExecutionAt);
|
||||
settings.currentTime = parseDateToEpoch(data.follower.currentDate);
|
||||
|
||||
if( settings.nextExecutionAtEpoch > settings.currentTime) {
|
||||
settings.isApprox = false;
|
||||
settings.tick = ( settings.nextExecutionAtEpoch - settings.currentTime) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
};
|
||||
|
||||
var getLeaderSettings = function(details, isFollower) {
|
||||
var leader = {};
|
||||
var leaderData = isFollower ? details.follower.leaderDetails.leader : details.leader;
|
||||
leader.replicationEnabled = leaderData.replicationEnabled == "true";
|
||||
leader.replicateAfter = leaderData.replicateAfter.join(", ");
|
||||
|
||||
if (leaderData.confFiles) {
|
||||
leader.files = [];
|
||||
var confFiles = leaderData.confFiles.split(',');
|
||||
for (var i=0; i<confFiles.length; i++) {
|
||||
var file = confFiles[i];
|
||||
var short = file;
|
||||
var title = file;
|
||||
if (file.indexOf(":")>=0) {
|
||||
title = file.replace(':', ' » ');
|
||||
var parts = file.split(':');
|
||||
if (isFollower) {
|
||||
short = parts[1];
|
||||
} else {
|
||||
short = parts[0];
|
||||
}
|
||||
}
|
||||
leader.files.push({title:title, name:short});
|
||||
}
|
||||
}
|
||||
return leader;
|
||||
}
|
||||
2023
solr/server/solr-webapp/webapp/js/angular/controllers/schema-designer.js
vendored
Normal file
2023
solr/server/solr-webapp/webapp/js/angular/controllers/schema-designer.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
713
solr/server/solr-webapp/webapp/js/angular/controllers/schema.js
vendored
Normal file
713
solr/server/solr-webapp/webapp/js/angular/controllers/schema.js
vendored
Normal file
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var cookie_schema_browser_autoload = 'schema-browser_autoload';
|
||||
|
||||
solrAdminApp.controller('SchemaController',
|
||||
function($scope, $routeParams, $location, $cookies, $timeout, Luke, Constants, Schema, Config) {
|
||||
$scope.resetMenu("schema", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.refresh = function () {
|
||||
Luke.schema({core: $routeParams.core}, function (schema) {
|
||||
Luke.raw({core: $routeParams.core}, function (index) {
|
||||
var data = mergeIndexAndSchemaData(index, schema.schema);
|
||||
|
||||
$scope.fieldsAndTypes = getFieldsAndTypes(data);
|
||||
$scope.is = {};
|
||||
|
||||
var search = $location.search();
|
||||
leftbar = {};
|
||||
$scope.isField = $scope.isDynamicField = $scope.isType = false;
|
||||
$scope.showing = true;
|
||||
if (search.field) {
|
||||
$scope.selectedType = "Field";
|
||||
$scope.is.field = true;
|
||||
$scope.name = search.field;
|
||||
leftbar.fields = [$scope.name];
|
||||
var field = data.fields[$scope.name];
|
||||
leftbar.types = [field.type];
|
||||
if (field.dynamicBase) leftbar.dynamicFields = [field.dynamicBase];
|
||||
if (field.copySources && field.copySources.length>0) {
|
||||
leftbar.copyFieldSources = sortedObjectArray(field.copySources.sort());
|
||||
}
|
||||
if (field.copyDests && field.copyDests.length>0) {
|
||||
leftbar.copyFieldDests = sortedObjectArray(field.copyDests.sort());
|
||||
}
|
||||
$scope.fieldOrType = "field=" + $scope.name;
|
||||
} else if (search["dynamic-field"]) {
|
||||
$scope.selectedType = "Dynamic Field";
|
||||
$scope.is.dynamicField = true;
|
||||
$scope.name = search["dynamic-field"];
|
||||
leftbar.dynamicFields = [$scope.name];
|
||||
leftbar.types = [data.dynamic_fields[$scope.name].type];
|
||||
$scope.fieldOrType = "dynamic-field=" + $scope.name;
|
||||
} else if (search.type) {
|
||||
$scope.selectedType = "Type";
|
||||
$scope.is.type = true;
|
||||
$scope.name = search.type;
|
||||
leftbar.types = [$scope.name];
|
||||
leftbar.fields = filterFields("fields", data, $scope.name);
|
||||
leftbar.dynamicFields = filterFields("dynamic_fields", data, $scope.name);
|
||||
$scope.fieldOrType = "type=" + $scope.name;
|
||||
} else {
|
||||
$scope.showing = false;
|
||||
}
|
||||
$scope.leftbar = leftbar;
|
||||
$scope.core = $routeParams.core;
|
||||
$scope.uniqueKeyField = data.unique_key_field;
|
||||
$scope.similarity = data.similarity;
|
||||
if ($scope.similarity && $scope.similarity.className) {
|
||||
$scope.similarity.className = shortenPackages($scope.similarity.className);
|
||||
}
|
||||
$scope.isUniqueKeyField = ($scope.selectedType == "Field" && $scope.name == $scope.uniqueKeyField);
|
||||
|
||||
$scope.display = getFieldProperties(data, $routeParams.core, $scope.is, $scope.name);
|
||||
$scope.analysis = getAnalysisInfo(data, $scope.is, $scope.name);
|
||||
|
||||
$scope.isAutoload = $cookies[cookie_schema_browser_autoload] == "true";
|
||||
if ($scope.isAutoload) {
|
||||
$scope.toggleTerms();
|
||||
}
|
||||
|
||||
$scope.types = Object.keys(schema.schema.types);
|
||||
});
|
||||
});
|
||||
Config.get({core: $routeParams.core}, function(data) {
|
||||
$scope.isSchemaUpdatable = (data.config.hasOwnProperty('schemaFactory') == false || data.config.schemaFactory.class == "ManagedIndexSchemaFactory");
|
||||
});
|
||||
};
|
||||
$scope.refresh();
|
||||
|
||||
$scope.selectFieldTypeManipulationOption = function() {
|
||||
$scope.fieldTypeObj = $scope.fieldTypeManipulationOption.template;
|
||||
}
|
||||
|
||||
$scope.showHelp = function (id) {
|
||||
if ($scope.helpId && ($scope.helpId === id || id === '')) {
|
||||
delete $scope.helpId;
|
||||
} else {
|
||||
$scope.helpId = id;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.selectFieldOrType = function() {
|
||||
$location.search($scope.fieldOrType);
|
||||
}
|
||||
|
||||
$scope.toggleAnalyzer = function(analyzer) {
|
||||
analyzer.show = !analyzer.show;
|
||||
}
|
||||
|
||||
$scope.loadTermInfo = function() {
|
||||
var params = {fl: $scope.name, core: $routeParams.core};
|
||||
if ($scope.topTermsCount) {
|
||||
params.numTerms = $scope.topTermsCount;
|
||||
}
|
||||
$scope.isLoadingTerms = true;
|
||||
Luke.field(params, function (data) {
|
||||
$scope.isLoadingTerms = false;
|
||||
$scope.termInfo = getTermInfo(data.fields[$scope.name]);
|
||||
if (!$scope.topTermsCount) {
|
||||
$scope.topTermsCount = $scope.termInfo.termCount;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleTerms = function() {
|
||||
$scope.showTerms = !$scope.showTerms;
|
||||
|
||||
if ($scope.showTerms) {
|
||||
$scope.loadTermInfo();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.loadAllTerms = function() {
|
||||
$scope.topTermsCount = $scope.termInfo.maxTerms;
|
||||
$scope.loadTermInfo();
|
||||
}
|
||||
|
||||
$scope.toggleAutoload = function() {
|
||||
$scope.isAutoload = !$scope.isAutoload;
|
||||
$cookies[cookie_schema_browser_autoload] = $scope.isAutoload;
|
||||
console.log("cookie: " + $cookies[cookie_schema_browser_autoload]);
|
||||
}
|
||||
|
||||
$scope.hideAll = function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.showAddDynamicField = false;
|
||||
$scope.showAddCopyField = false;
|
||||
$scope.showManipulateFieldType = false;
|
||||
}
|
||||
|
||||
$scope.toggleAddField = function() {
|
||||
if ($scope.showAddField && $scope.adding == "field") {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddField = true;
|
||||
$scope.adding = "field";
|
||||
|
||||
$scope.newField = {
|
||||
stored: "true",
|
||||
indexed: "true",
|
||||
uninvertible: "true"
|
||||
}
|
||||
delete $scope.addErrors;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addField = function() {
|
||||
delete $scope.addErrors;
|
||||
var data = {"add-field": $scope.newField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addErrors === "string") {
|
||||
$scope.addErrors = [$scope.addErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.added = true;
|
||||
$timeout(function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.added = false;
|
||||
$scope.refresh();
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleAddDynamicField = function() {
|
||||
if ($scope.showAddField && $scope.adding == "dynamicField") {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddField = true;
|
||||
$scope.adding = "dynamicField";
|
||||
|
||||
$scope.newField = {
|
||||
stored: "true",
|
||||
indexed: "true"
|
||||
}
|
||||
delete $scope.addErrors;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addDynamicField = function() {
|
||||
delete $scope.addErrors;
|
||||
var data = {"add-dynamic-field": $scope.newField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addErrors === "string") {
|
||||
$scope.addErrors = [$scope.addErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.added = true;
|
||||
$timeout(function() {
|
||||
$scope.showAddField = false;
|
||||
$scope.added = false;
|
||||
$scope.refresh();
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleAddCopyField = function() {
|
||||
if ($scope.showAddCopyField) {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showAddCopyField = true;
|
||||
|
||||
$scope.copyField = {};
|
||||
delete $scope.addCopyFieldErrors;
|
||||
}
|
||||
}
|
||||
$scope.addCopyField = function() {
|
||||
delete $scope.addCopyFieldErrors;
|
||||
var data = {"add-copy-field": $scope.copyField};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.addCopyFieldErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.addCopyFieldErrors === "string") {
|
||||
$scope.addCopyFieldErrors = [$scope.addCopyFieldErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.showAddCopyField = false;
|
||||
$timeout($scope.refresh, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleDelete = function() {
|
||||
if ($scope.showDelete) {
|
||||
$scope.showDelete = false;
|
||||
} else {
|
||||
if ($scope.is.field) {
|
||||
$scope.deleteData = {'delete-field': {name: $scope.name}};
|
||||
} else if ($scope.is.dynamicField) {
|
||||
$scope.deleteData = {'delete-dynamic-field': {name: $scope.name}};
|
||||
} else {
|
||||
alert("TYPE NOT KNOWN");
|
||||
}
|
||||
$scope.showDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.delete = function() {
|
||||
Schema.post({core: $routeParams.core}, $scope.deleteData, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.deleteErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.deleteErrors === "string") {
|
||||
$scope.deleteErrors = [$scope.deleteErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.deleted = true;
|
||||
$timeout(function() {
|
||||
$location.search("");
|
||||
}, 1500
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.toggleDeleteCopyField = function(field) {
|
||||
field.show = !field.show;
|
||||
delete field.errors;
|
||||
}
|
||||
$scope.deleteCopyField = function(field, source, dest) {
|
||||
data = {'delete-copy-field': {source: source, dest: dest}};
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
field.errors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.deleteErrors === "string") {
|
||||
field.errors = [field.errors];
|
||||
}
|
||||
} else {
|
||||
field.deleted = true;
|
||||
$timeout($scope.refresh, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.toggleManipulateFieldType = function() {
|
||||
if ($scope.showManipulateFieldType) {
|
||||
$scope.hideAll();
|
||||
} else {
|
||||
$scope.hideAll();
|
||||
$scope.showManipulateFieldType = true;
|
||||
|
||||
$scope.adding = "fieldType";
|
||||
|
||||
$scope.fieldTypeObj = ""
|
||||
delete $scope.addErrors;
|
||||
}
|
||||
$scope.fieldTypeManipulationOptions = getFieldTypeManipulationOptions();
|
||||
$scope.fieldTypeManipulationOption = $scope.fieldTypeManipulationOptions[0];
|
||||
$scope.selectFieldTypeManipulationOption();
|
||||
}
|
||||
|
||||
$scope.manipulateFieldType = function() {
|
||||
delete $scope.manipulateFieldTypeErrors;
|
||||
var data = JSON.parse($scope.fieldTypeObj);
|
||||
Schema.post({core: $routeParams.core}, data, function(data) {
|
||||
if (data.errors) {
|
||||
$scope.manipulateFieldTypeErrors = data.errors[0].errorMessages;
|
||||
if (typeof $scope.manipulateFieldTypeErrors === "string") {
|
||||
$scope.manipulateFieldTypeErrors = [$scope.manipulateFieldTypeErrors];
|
||||
}
|
||||
} else {
|
||||
$scope.added = true;
|
||||
$timeout(function() {
|
||||
$scope.showManipulateFieldType = false;
|
||||
$scope.added = false;
|
||||
$scope.refresh();
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var getFieldsAndTypes = function(data) {
|
||||
var fieldsAndTypes = [];
|
||||
var fields = Object.keys(data.fields).sort();
|
||||
for (var i in fields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Fields",
|
||||
value: "field=" + fields[i],
|
||||
label: fields[i]
|
||||
});
|
||||
}
|
||||
var dynamic_fields = Object.keys(data.dynamic_fields).sort();
|
||||
for (var i in dynamic_fields) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Dynamic Fields",
|
||||
value: "dynamic-field=" + dynamic_fields[i],
|
||||
label: dynamic_fields[i]
|
||||
});
|
||||
}
|
||||
var types = Object.keys(data.types).sort();
|
||||
for (var i in types) {
|
||||
fieldsAndTypes.push({
|
||||
group: "Types",
|
||||
value: "type=" + types[i],
|
||||
label: types[i]
|
||||
});
|
||||
}
|
||||
return fieldsAndTypes;
|
||||
};
|
||||
|
||||
var filterFields = function(type, data, name) {
|
||||
var fields = [];
|
||||
for (var i in data.types[name].fields) {
|
||||
var field = data.types[name].fields[i];
|
||||
if (data[type][field]) {
|
||||
fields.push(field)
|
||||
}
|
||||
}
|
||||
return fields.sort();
|
||||
}
|
||||
|
||||
var mergeIndexAndSchemaData = function(index, schema) {
|
||||
|
||||
var data = {
|
||||
unique_key_field: null,
|
||||
similarity: null,
|
||||
key: {},
|
||||
fields: {},
|
||||
dynamic_fields: {},
|
||||
types: {},
|
||||
relations: {
|
||||
f_df: {},
|
||||
f_t: {},
|
||||
df_f: {},
|
||||
df_t: {},
|
||||
t_f: {},
|
||||
t_df: {}
|
||||
}
|
||||
};
|
||||
|
||||
data.fields = index.fields;
|
||||
|
||||
data.key = index.info.key;
|
||||
|
||||
data.unique_key_field = schema.uniqueKeyField;
|
||||
data.similarity = schema.similarity;
|
||||
|
||||
data.dynamic_fields = schema.dynamicFields;
|
||||
data.types = schema.types;
|
||||
|
||||
for (var field in schema.fields) {
|
||||
data.fields[field] =
|
||||
$.extend({}, data.fields[field], schema.fields[field]);
|
||||
}
|
||||
|
||||
for (var field in data.fields) {
|
||||
var copy_dests = data.fields[field].copyDests;
|
||||
for (var i in copy_dests) {
|
||||
var copy_dest = copy_dests[i];
|
||||
if (!data.fields[copy_dest]) {
|
||||
data.fields[copy_dest] = {
|
||||
partial: true,
|
||||
copySources: []
|
||||
};
|
||||
}
|
||||
|
||||
if (data.fields[copy_dest].partial) {
|
||||
data.fields[copy_dest].copySources.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
var copy_sources = data.fields[field].copySources;
|
||||
for (var i in copy_sources) {
|
||||
var copy_source = copy_sources[i];
|
||||
if (!data.fields[copy_source]) {
|
||||
data.fields[copy_source] = {
|
||||
partial: true,
|
||||
copyDests: []
|
||||
};
|
||||
}
|
||||
|
||||
if (data.fields[copy_source].partial) {
|
||||
data.fields[copy_source].copyDests.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
data.relations.f_t[field] = data.fields[field].type;
|
||||
|
||||
if (!data.relations.t_f[data.fields[field].type]) {
|
||||
data.relations.t_f[data.fields[field].type] = [];
|
||||
}
|
||||
data.relations.t_f[data.fields[field].type].push(field);
|
||||
|
||||
if (data.fields[field].dynamicBase) {
|
||||
data.relations.f_df[field] = data.fields[field].dynamicBase;
|
||||
|
||||
if (!data.relations.df_f[data.fields[field].dynamicBase]) {
|
||||
data.relations.df_f[data.fields[field].dynamicBase] = [];
|
||||
}
|
||||
data.relations.df_f[data.fields[field].dynamicBase].push(field);
|
||||
}
|
||||
}
|
||||
|
||||
for (var dynamic_field in data.dynamic_fields) {
|
||||
data.relations.df_t[dynamic_field] = data.dynamic_fields[dynamic_field].type;
|
||||
|
||||
if (!data.relations.t_df[data.dynamic_fields[dynamic_field].type]) {
|
||||
data.relations.t_df[data.dynamic_fields[dynamic_field].type] = [];
|
||||
}
|
||||
data.relations.t_df[data.dynamic_fields[dynamic_field].type].push(dynamic_field);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
var getFieldProperties = function(data, core, is, name) {
|
||||
|
||||
var display = {};
|
||||
|
||||
display.partialState = is.field && !!data.fields[name].partial;
|
||||
|
||||
display.columns = [];
|
||||
display.rows = [];
|
||||
var allFlags = "";
|
||||
|
||||
var addRow = function(name, flags) {
|
||||
if (flags[0]!='(') {
|
||||
display.rows.push({name:name, flags:flags});
|
||||
for (var i in flags) {
|
||||
if (flags[i]!="-" && allFlags.indexOf(flags[i])<0) {
|
||||
allFlags+=flags[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
display.rows.push({name:name, comment:flags});
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the rows for our field property table
|
||||
if (is.field && data.fields[name]) {
|
||||
if (data.fields[name].flags) {
|
||||
addRow('Properties', data.fields[name].flags);
|
||||
}
|
||||
if (data.fields[name].schema) {
|
||||
addRow('Schema', data.fields[name].schema);
|
||||
}
|
||||
if (data.fields[name].index) {
|
||||
addRow('Index', data.fields[name].index);
|
||||
}
|
||||
display.docs = data.fields[name].docs;
|
||||
display.docsUrl = "#/" + core + "/query?q=" + name + ":[* TO *]";
|
||||
display.distinct = data.fields[name].distinct;
|
||||
display.positionIncrementGap = data.fields[name].positionIncrementGap;
|
||||
if (data.types[data.fields[name].type]) {
|
||||
display.similarity = data.types[data.fields[name].type].similarity;
|
||||
} else {
|
||||
display.similarity = null;
|
||||
}
|
||||
} else if (is.dynamicField && data.dynamic_fields[name] && data.dynamic_fields[name].flags) {
|
||||
addRow('Properties', data.dynamic_fields[name].flags);
|
||||
display.similarity = data.types[data.dynamic_fields[name].type].similarity;
|
||||
} else if (is.type && data.types[name]) {
|
||||
display.similarity = data.types[name].similarity;
|
||||
}
|
||||
if (display.similarity && display.similarity.className) {
|
||||
display.similarity.className = shortenPackages(display.similarity.className);
|
||||
}
|
||||
|
||||
// identify columns in field property table:
|
||||
for (var key in data.key) {
|
||||
if (allFlags.indexOf(key)>=0) {
|
||||
display.columns.push({key: key, name: data.key[key]});
|
||||
}
|
||||
}
|
||||
|
||||
// identify rows and cell values in field property table:
|
||||
for (var i in display.rows) {
|
||||
var row = display.rows[i];
|
||||
row.cells = [];
|
||||
|
||||
if (!row.flags) {
|
||||
continue; // Match the special case in the LukeRequestHandler
|
||||
}
|
||||
|
||||
for (var j in display.columns) {
|
||||
var flag = display.columns[j].key;
|
||||
row.cells.push({key: flag, value: row.flags.indexOf(flag)>=0});
|
||||
}
|
||||
}
|
||||
|
||||
return display;
|
||||
};
|
||||
|
||||
var getAnalysisInfo = function(data, is, name) {
|
||||
|
||||
var analysis = {};
|
||||
|
||||
if (is.field) {
|
||||
var type = data.relations.f_t[name];
|
||||
analysis.query = "analysis.fieldname=" + name;
|
||||
}
|
||||
else if (is.dynamicField) {
|
||||
var type = data.relations.df_t[name];
|
||||
analysis.query = "analysis.dynamicfield=" + name;
|
||||
}
|
||||
else if (is.type) {
|
||||
var type = name;
|
||||
analysis.query = "analysis.fieldtype=" + name;
|
||||
}
|
||||
|
||||
var processComponentType = function (label, key, componentTypeData) {
|
||||
if (componentTypeData) {
|
||||
var components = [];
|
||||
for (var componentName in componentTypeData) {
|
||||
var componentData = componentTypeData[componentName];
|
||||
var component = {className: componentData.className, args:[]};
|
||||
if (componentData.args) {
|
||||
for (var argName in componentData.args) {
|
||||
var argValue = componentData.args[argName];
|
||||
if (argValue == "1" || argValue == "true") {
|
||||
component.args.push({name: argName, booleanValue:true});
|
||||
} else if (argValue == "0" || argValue == "false") {
|
||||
component.args.push({name: argName, booleanValue:false});
|
||||
} else {
|
||||
component.args.push({name: argName, value:argValue});
|
||||
}
|
||||
}
|
||||
}
|
||||
components.push(component);
|
||||
}
|
||||
return {label: label, key: key, components: components};
|
||||
} else {
|
||||
return {label: label, key: key};
|
||||
}
|
||||
}
|
||||
|
||||
var buildAnalyzer = function (analyzerData) {
|
||||
var analyzer = {};
|
||||
analyzer.className = analyzerData.className;
|
||||
analyzer.componentTypes = [];
|
||||
if (analyzerData.tokenizer) {
|
||||
analyzer.componentTypes.push(processComponentType("Char Filters", "charFilters", analyzerData.charFilters));
|
||||
analyzer.componentTypes.push(processComponentType("Tokenizer", "tokenizer", {tokenizer: analyzerData.tokenizer}));
|
||||
analyzer.componentTypes.push(processComponentType("Token Filters", "tokenFilters", analyzerData.filters));
|
||||
}
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
analysis.data = data.types[type];
|
||||
if (analysis.data) {
|
||||
analysis.analyzers = [
|
||||
{key: "index", name: "Index", detail: buildAnalyzer(analysis.data.indexAnalyzer)},
|
||||
{key: "query", name: "Query", detail: buildAnalyzer(analysis.data.queryAnalyzer)}
|
||||
];
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
var getTermInfo = function(data) {
|
||||
|
||||
var termInfo = {};
|
||||
if (data && data.topTerms) {
|
||||
termInfo.topTerms = [];
|
||||
|
||||
var currentGroup = {count: 0}
|
||||
for (var i = 0; i < data.topTerms.length; i += 2) {
|
||||
var count = data.topTerms[i + 1];
|
||||
if (currentGroup.count != count) {
|
||||
currentGroup = {count: count, terms: []};
|
||||
termInfo.topTerms.push(currentGroup);
|
||||
}
|
||||
currentGroup.terms.push(data.topTerms[i]);
|
||||
}
|
||||
termInfo.termCount = data.topTerms.length / 2;
|
||||
termInfo.maxTerms = data.distinct;
|
||||
}
|
||||
|
||||
if(data && data.histogram) {
|
||||
termInfo.histogram = [];
|
||||
termInfo.histogramMax = 0;
|
||||
for (var i = 0; i < data.histogram.length; i += 2) {
|
||||
termInfo.histogram.push({key: data.histogram[i], value: data.histogram[i + 1]});
|
||||
termInfo.histogramMax = Math.max(termInfo.histogramMax, data.histogram[i + 1]);
|
||||
}
|
||||
}
|
||||
return termInfo;
|
||||
};
|
||||
|
||||
var getFieldTypeManipulationOptions = function() {
|
||||
return [
|
||||
{
|
||||
value: "Add FieldType Template",
|
||||
label: "Add FieldType",
|
||||
template: "{\n" +
|
||||
" \"add-field-type\": {\n" +
|
||||
" \"name\": \"myNewTxtField\",\n" +
|
||||
" \"class\": \"solr.TextField\",\n" +
|
||||
" \"positionIncrementGap\": \"100\",\n" +
|
||||
" \"analyzer\": {\n" +
|
||||
" \"charFilters\": [\n" +
|
||||
" {\n" +
|
||||
" \"class\": \"solr.PatternReplaceCharFilterFactory\",\n" +
|
||||
" \"replacement\": \"$1$1\",\n" +
|
||||
" \"pattern\": \"([a-zA-Z])\\\\\\\\1+\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"tokenizer\": {\n" +
|
||||
" \"class\": \"solr.WhitespaceTokenizerFactory\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
},
|
||||
{
|
||||
value: "Delete FieldType Template",
|
||||
label: "Delete FieldType",
|
||||
template: "{\n" +
|
||||
" \"delete-field-type\": {\n" +
|
||||
" \"name\": \"myNewTxtField\"\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
},
|
||||
{
|
||||
value: "Replace FieldType Template",
|
||||
label: "Replace FieldType",
|
||||
template: "{\n" +
|
||||
" \"replace-field-type\": {\n" +
|
||||
" \"name\": \"myNewTxtField\",\n" +
|
||||
" \"class\": \"solr.TextField\",\n" +
|
||||
" \"positionIncrementGap\": \"100\",\n" +
|
||||
" \"analyzer\": {\n" +
|
||||
" \"tokenizer\": {\n" +
|
||||
" \"class\": \"solr.StandardTokenizerFactory\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
var sortedObjectArray = function(list) {
|
||||
var objarr = [];
|
||||
for (var i in list) {
|
||||
objarr.push({"name": list[i]});
|
||||
}
|
||||
return objarr;
|
||||
};
|
||||
|
||||
var shortenPackages = function(className) {
|
||||
return className.replace("org.apache.solr", "o.a.s").replace("org.apache.lucene", "o.a.l");
|
||||
};
|
||||
1245
solr/server/solr-webapp/webapp/js/angular/controllers/security.js
vendored
Normal file
1245
solr/server/solr-webapp/webapp/js/angular/controllers/security.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
99
solr/server/solr-webapp/webapp/js/angular/controllers/segments.js
vendored
Normal file
99
solr/server/solr-webapp/webapp/js/angular/controllers/segments.js
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var MB_FACTOR = 1024*1024;
|
||||
|
||||
solrAdminApp.controller('SegmentsController', function($scope, $routeParams, $interval, Segments, Constants) {
|
||||
$scope.resetMenu("segments", Constants.IS_CORE_PAGE);
|
||||
|
||||
$scope.refresh = function() {
|
||||
|
||||
Segments.get({core: $routeParams.core}, function(data) {
|
||||
var segments = data.segments;
|
||||
|
||||
var segmentSizeInBytesMax = getLargestSegmentSize(segments);
|
||||
$scope.segmentMB = Math.floor(segmentSizeInBytesMax / MB_FACTOR);
|
||||
$scope.xaxis = calculateXAxis(segmentSizeInBytesMax);
|
||||
|
||||
$scope.documentCount = 0;
|
||||
$scope.deletionCount = 0;
|
||||
|
||||
$scope.segments = [];
|
||||
for (var name in segments) {
|
||||
var segment = segments[name];
|
||||
|
||||
var segmentSizeInBytesLog = Math.log(segment.sizeInBytes);
|
||||
var segmentSizeInBytesMaxLog = Math.log(segmentSizeInBytesMax);
|
||||
|
||||
segment.totalSize = Math.floor((segmentSizeInBytesLog / segmentSizeInBytesMaxLog ) * 100);
|
||||
|
||||
segment.deletedDocSize = Math.floor((segment.delCount / segment.size) * segment.totalSize);
|
||||
if (segment.delDocSize <= 0.001) delete segment.deletedDocSize;
|
||||
|
||||
segment.aliveDocSize = segment.totalSize - segment.deletedDocSize;
|
||||
|
||||
$scope.segments.push(segment);
|
||||
|
||||
$scope.documentCount += segment.size;
|
||||
$scope.deletionCount += segment.delCount;
|
||||
}
|
||||
$scope.deletionsPercentage = calculateDeletionsPercentage($scope.documentCount, $scope.deletionCount);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleAutoRefresh = function() {
|
||||
$scope.autorefresh = !$scope.autorefresh;
|
||||
if ($scope.autorefresh) {
|
||||
$scope.interval = $interval($scope.refresh, 1000);
|
||||
var onRouteChangeOff = $scope.$on('$routeChangeStart', function() {
|
||||
$interval.cancel($scope.interval);
|
||||
onRouteChangeOff();
|
||||
});
|
||||
|
||||
} else if ($scope.interval) {
|
||||
$interval.cancel($scope.interval);
|
||||
}
|
||||
};
|
||||
$scope.refresh();
|
||||
});
|
||||
|
||||
var calculateXAxis = function(segmentInBytesMax) {
|
||||
var steps = [];
|
||||
var log = Math.log(segmentInBytesMax);
|
||||
|
||||
for (var j=0, step=log/4; j<3; j++, step+=log/4) {
|
||||
steps.push({pos:j, value:Math.floor((Math.pow(Math.E, step))/MB_FACTOR)})
|
||||
}
|
||||
return steps;
|
||||
};
|
||||
|
||||
var getLargestSegmentSize = function(segments) {
|
||||
var max = 0;
|
||||
for (var name in segments) {
|
||||
max = Math.max(max, segments[name].sizeInBytes);
|
||||
}
|
||||
return max;
|
||||
};
|
||||
|
||||
var calculateDeletionsPercentage = function(docCount, delCount) {
|
||||
if (docCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
var percent = delCount / docCount * 100;
|
||||
return Math.round(percent * 100) / 100;
|
||||
}
|
||||
};
|
||||
88
solr/server/solr-webapp/webapp/js/angular/controllers/sqlquery.js
vendored
Normal file
88
solr/server/solr-webapp/webapp/js/angular/controllers/sqlquery.js
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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('SQLQueryController',
|
||||
function($scope, $routeParams, $location, Query, Constants) {
|
||||
|
||||
$scope.resetMenu("sqlquery", Constants.IS_COLLECTION_PAGE);
|
||||
$scope.qt = "sql";
|
||||
$scope.doExplanation = false
|
||||
$scope.gridOptions = {
|
||||
enableSorting: false,
|
||||
enableRowHashing:false,
|
||||
enableColumnMenus:false,
|
||||
columnDefs:[],
|
||||
data:[],
|
||||
onRegisterApi: function(gridApi) {
|
||||
$scope.gridApi = gridApi;
|
||||
}
|
||||
};
|
||||
$scope.hostPortContext = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // For display only
|
||||
$scope.doQuery = function() {
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.handler = $scope.qt;
|
||||
|
||||
var stmt = $scope.stmt
|
||||
|
||||
if(!stmt.toLowerCase().replace(/(\r\n|\n|\r)/gm," ").includes(' limit ')) {
|
||||
params.stmt = [stmt + " limit 10"]
|
||||
} else {
|
||||
params.stmt = [$scope.stmt]
|
||||
}
|
||||
|
||||
$scope.lang = "json";
|
||||
$scope.response = null;
|
||||
$scope.url = "";
|
||||
$scope.gridOptions.data =[]
|
||||
$scope.gridOptions.columnDefs = []
|
||||
|
||||
var url = Query.url(params);
|
||||
Query.query(params, function(data) {
|
||||
|
||||
var jsonData = JSON.parse(data.toJSON().data);
|
||||
$scope.lang = "json";
|
||||
$scope.url = url;
|
||||
$scope.sqlError = null;
|
||||
$scope.sqlData = [];
|
||||
if(jsonData != undefined){
|
||||
var docs = jsonData['result-set'].docs
|
||||
//get all docs
|
||||
for (var i = 0; i < docs.length; i++) {
|
||||
var doc = docs[i]
|
||||
//get all the properties
|
||||
if(doc.hasOwnProperty("EOF")){
|
||||
if(doc.hasOwnProperty("EXCEPTION")){
|
||||
$scope.sqlError = doc.EXCEPTION
|
||||
}
|
||||
} else {
|
||||
$scope.gridOptions.data.push(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Build the columnFields from data
|
||||
var fields = $scope.gridOptions.data[1];
|
||||
for (var property in fields) {
|
||||
if (fields.hasOwnProperty(property)) {
|
||||
$scope.gridOptions.columnDefs.push({"name":property, "type":{}})
|
||||
}
|
||||
}
|
||||
$scope.gridApi.core.notifyDataChange
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
239
solr/server/solr-webapp/webapp/js/angular/controllers/stream.js
vendored
Normal file
239
solr/server/solr-webapp/webapp/js/angular/controllers/stream.js
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
solrAdminApp.controller('StreamController',
|
||||
function($scope, $routeParams, $location, Query, Constants) {
|
||||
|
||||
$scope.resetMenu("stream", Constants.IS_COLLECTION_PAGE);
|
||||
|
||||
$scope.stream = {
|
||||
wt: 'json',
|
||||
expr: $scope.expr,
|
||||
indent: 'on'
|
||||
};
|
||||
$scope.qt = "stream";
|
||||
$scope.doExplanation = false
|
||||
|
||||
$scope.doStream = function() {
|
||||
|
||||
var params = {};
|
||||
params.core = $routeParams.core;
|
||||
params.handler = $scope.qt;
|
||||
params.expr = [$scope.expr]
|
||||
if($scope.doExplanation){
|
||||
params.explain = [$scope.doExplanation]
|
||||
}
|
||||
|
||||
$scope.lang = "json";
|
||||
$scope.response = null;
|
||||
$scope.url = "";
|
||||
|
||||
var url = Query.url(params);
|
||||
|
||||
Query.query(params, function(data) {
|
||||
|
||||
var jsonData = JSON.parse(data.toJSON().data);
|
||||
if (undefined != jsonData["explanation"]) {
|
||||
$scope.showExplanation = true;
|
||||
|
||||
streamGraphSubController($scope, jsonData["explanation"])
|
||||
delete jsonData["explanation"]
|
||||
} else {
|
||||
$scope.showExplanation = false;
|
||||
}
|
||||
|
||||
data.data = JSON.stringify(jsonData,null,2);
|
||||
|
||||
$scope.lang = "json";
|
||||
$scope.response = data;
|
||||
$scope.url = url;
|
||||
$scope.hostPortContext = $location.absUrl().substr(0,$location.absUrl().indexOf("#")); // For display only
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
if ($location.search().expr) {
|
||||
$scope.expr = $location.search()["expr"];
|
||||
$scope.doStream();
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
var streamGraphSubController = function($scope, explanation) {
|
||||
$scope.showGraph = true;
|
||||
$scope.pos = 0;
|
||||
$scope.rows = 8;
|
||||
|
||||
$scope.resetGraph = function() {
|
||||
$scope.pos = 0;
|
||||
$scope.initGraph();
|
||||
}
|
||||
|
||||
$scope.initGraph = function(explanation) {
|
||||
|
||||
data = explanation
|
||||
|
||||
var leafCount = 0;
|
||||
var maxDepth = 0;
|
||||
var rootNode = {};
|
||||
|
||||
leafCount = 0;
|
||||
|
||||
let recurse = function(dataNode, depth) {
|
||||
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
}
|
||||
|
||||
let graphNode = {
|
||||
name: dataNode.expressionNodeId,
|
||||
implementingClass: 'unknown',
|
||||
data: {}
|
||||
};
|
||||
|
||||
["expressionNodeId", "expressionType", "functionName", "implementingClass", "expression", "note", "helpers"].forEach(function(key) {
|
||||
graphNode.data[key] = dataNode[key];
|
||||
});
|
||||
|
||||
if (dataNode.children && dataNode.children.length > 0) {
|
||||
graphNode.children = [];
|
||||
dataNode.children.forEach(function(n) {
|
||||
graphNode.children.push(recurse(n, depth + 1));
|
||||
});
|
||||
} else {
|
||||
++leafCount;
|
||||
}
|
||||
|
||||
return graphNode;
|
||||
}
|
||||
|
||||
$scope.showPaging = false;
|
||||
$scope.isRadial = false;
|
||||
$scope.explanationData = recurse(data, 1);
|
||||
|
||||
$scope.depth = maxDepth + 1;
|
||||
$scope.leafCount = leafCount;
|
||||
};
|
||||
|
||||
$scope.initGraph(explanation);
|
||||
};
|
||||
|
||||
solrAdminApp.directive('explanationGraph', function(Constants) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: {
|
||||
data: "=",
|
||||
leafCount: "=",
|
||||
depth: "="
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
var helper_path_class = function(p) {
|
||||
var classes = ['link'];
|
||||
|
||||
return classes.join(' ');
|
||||
};
|
||||
|
||||
var helper_node_class = function(d) {
|
||||
var classes = ['node'];
|
||||
|
||||
if (d.data && d.data.expressionType) {
|
||||
classes.push(d.data.expressionType);
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
};
|
||||
|
||||
var helper_node_text = function(d) {
|
||||
if (d.data && d.data.functionName) {
|
||||
return d.data.functionName;
|
||||
}
|
||||
|
||||
return d.name
|
||||
};
|
||||
|
||||
var helper_tooltip = function(d) {
|
||||
|
||||
return [
|
||||
"Function: " + d.data.functionName,
|
||||
"Type: " + d.data.expressionType,
|
||||
"Class: " + d.data.implementingClass.replace("org.apache.solr.client.solrj.io", "o.a.s.c.s.i"),
|
||||
"=============",
|
||||
d.data.expression
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
scope.$watch("data", function(newValue, oldValue) {
|
||||
if (newValue) {
|
||||
flatGraph(element, scope.data, scope.depth, scope.leafCount);
|
||||
}
|
||||
});
|
||||
|
||||
var flatGraph = function(element, graphData, depth, leafCount) {
|
||||
var w = 100 + (depth * 100),
|
||||
h = leafCount * 40;
|
||||
|
||||
var tree = d3.layout.tree().size([h, w]);
|
||||
|
||||
var diagonal = d3.svg.diagonal().projection(function(d) {
|
||||
return [d.y * .7, d.x];
|
||||
});
|
||||
|
||||
d3.select('#canvas', element).html('');
|
||||
var vis = d3.select('#canvas', element).append('svg')
|
||||
.attr('width', w)
|
||||
.attr('height', h)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(25, 0)');
|
||||
|
||||
var nodes = tree.nodes(graphData);
|
||||
|
||||
var link = vis.selectAll('path.link')
|
||||
.data(tree.links(nodes))
|
||||
.enter().append('path')
|
||||
.attr('class', helper_path_class)
|
||||
.attr('d', diagonal);
|
||||
|
||||
var node = vis.selectAll('g.node')
|
||||
.data(nodes)
|
||||
.enter().append('g')
|
||||
.attr('class', helper_node_class)
|
||||
.attr('transform', function(d) {
|
||||
return 'translate(' + d.y * .7 + ',' + d.x + ')';
|
||||
})
|
||||
|
||||
node.append('circle')
|
||||
.attr('r', 4.5);
|
||||
|
||||
node.append('title')
|
||||
.text(helper_tooltip);
|
||||
|
||||
node.append('text')
|
||||
.attr('dx', function(d) {
|
||||
return 8;
|
||||
})
|
||||
.attr('dy', function(d) {
|
||||
return 5;
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
return 'start';
|
||||
})
|
||||
.text(helper_node_text)
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
50
solr/server/solr-webapp/webapp/js/angular/controllers/threads.js
vendored
Normal file
50
solr/server/solr-webapp/webapp/js/angular/controllers/threads.js
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
solrAdminApp.controller('ThreadsController',
|
||||
function($scope, Threads, Constants){
|
||||
$scope.resetMenu("threads", Constants.IS_ROOT_PAGE);
|
||||
$scope.refresh = function() {
|
||||
Threads.get(function(data) {
|
||||
var threadDump = data.system.threadDump;
|
||||
var threads = [];
|
||||
for (var i=1; i<threadDump.length; i+=2) {
|
||||
var thread = threadDump[i];
|
||||
if (!!thread.stackTrace) {
|
||||
var stackTrace = [];
|
||||
for (var j=0; j<thread.stackTrace.length; j++) {
|
||||
var trace = thread.stackTrace[j].replace("(", "\u200B("); // allow wrapping to happen, \u200B is a zero-width space
|
||||
stackTrace.push({id:thread.id + ":" + j, trace: trace});
|
||||
}
|
||||
thread.stackTrace = stackTrace;
|
||||
}
|
||||
threads.push(thread);
|
||||
}
|
||||
$scope.threads = threads;
|
||||
});
|
||||
};
|
||||
$scope.toggleStacktrace = function(thread) {
|
||||
thread.showStackTrace = !thread.showStackTrace;
|
||||
};
|
||||
$scope.toggleStacktraces = function() {
|
||||
$scope.showAllStacktraces = !$scope.showAllStacktraces;
|
||||
for (var i=0; i<$scope.threads.length; i++) {
|
||||
$scope.threads[i].showStackTrace = $scope.showAllStacktraces;
|
||||
}
|
||||
};
|
||||
$scope.refresh();
|
||||
});
|
||||
37
solr/server/solr-webapp/webapp/js/angular/controllers/unknown.js
vendored
Normal file
37
solr/server/solr-webapp/webapp/js/angular/controllers/unknown.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller is called whenever no other routes match.
|
||||
* It is a place to intercept to look for special flows such as authentication callbacks (that do not support fragment in URL).
|
||||
* Normal action is to redirect to dashboard "/" if no login is in progress
|
||||
*/
|
||||
solrAdminApp.controller('UnknownController',
|
||||
['$scope', '$window', '$routeParams', '$location', 'Constants', 'AuthenticationService',
|
||||
function($scope, $window, $routeParams, $location, Constants, AuthenticationService) {
|
||||
var fragment = $window.location.hash.startsWith("#/") ? $window.location.hash.substring(2) : $window.location.hash;
|
||||
// Check if the URL is actually a callback from Identiy provider
|
||||
if (AuthenticationService.isJwtCallback(fragment)) {
|
||||
console.log("Detected an authentication callback, redirecting to /#/login/callback");
|
||||
$location.path("/login/callback").hash(fragment);
|
||||
} else {
|
||||
console.log("Redirecting from unknown path " + fragment + " to Dashboard");
|
||||
$location.path("/").hash("");
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
Reference in New Issue
Block a user