| /* |
| 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; } |
| */ |