/* | |
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.defaultSearchField = data.default_search_field; | |
$scope.uniqueKeyField = data.unique_key_field; | |
$scope.isDefaultSearchField = ($scope.selectedType == "Field" && $scope.name == $scope.defaultSearchField); | |
$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.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.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" | |
} | |
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); | |
} | |
}); | |
} | |
} | |
); | |
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 = { | |
default_search_field: null, | |
unique_key_field: 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.default_search_field = schema.defaultSearchField; | |
data.unique_key_field = schema.uniqueKeyField; | |
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, field) { | |
var display = {}; | |
display.partialState = is.field && !!data.fields[field].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[field]) { | |
if (data.fields[field].flags) { | |
addRow('Properties', data.fields[field].flags); | |
} | |
if (data.fields[field].schema) { | |
addRow('Schema', data.fields[field].schema); | |
} | |
if (data.fields[field].index) { | |
addRow('Index', data.fields[field].index); | |
} | |
display.docs = data.fields[field].docs; | |
display.docsUrl = "#/" + core + "/query?q=" + field + ":[* TO *]"; | |
display.distinct = data.fields[field].distinct; | |
display.positionIncrementGap = data.fields[field].positionIncrementGap; | |
display.similarity = data.fields[field].similarity; | |
} else if (is.dynamicField && data.dynamic_fields[field] && data.dynamic_fields[field].flags) { | |
addRow('Properties', data.dynamic_fields[field].flags); | |
} | |
// 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.fieldtype=" + type; | |
} | |
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 sortedObjectArray = function(list) { | |
var objarr = []; | |
for (var i in list) { | |
objarr.push({"name": list[i]}); | |
} | |
return objarr; | |
} | |
/* | |
var get_width = function get_width() | |
{ | |
return $( this ).width(); | |
} | |
var max_width = 10 + Math.max.apply( Math, $( 'p', topterms_table_element ).map( get_width ).get() ); | |
topterms: | |
p { width: {{maxWidth}}px !important; } | |
ul { margin-left: {{max_width + 5 }}px !important; } | |
var max_width = 10 + Math.max.apply( Math, $( 'dt', histogram_holder_element ).map( get_width ).get() ); | |
histogram_holder: | |
ul { margin-left: {{maxWidth}}px !important; } | |
li dt { left: {{-maxWidth}}px !important; width: {{maxWidth}}px !important; } | |
*/ |