kibana-123
Version:
Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic
180 lines (150 loc) • 6.41 kB
JavaScript
import 'ui/field_format_editor';
import 'angular-bootstrap-colorpicker';
import 'angular-bootstrap-colorpicker/css/colorpicker.css';
import _ from 'lodash';
import RegistryFieldFormatsProvider from 'ui/registry/field_formats';
import IndexPatternsFieldProvider from 'ui/index_patterns/_field';
import uiModules from 'ui/modules';
import fieldEditorTemplate from 'ui/field_editor/field_editor.html';
import chrome from 'ui/chrome';
import IndexPatternsCastMappingTypeProvider from 'ui/index_patterns/_cast_mapping_type';
import { scriptedFields as docLinks } from '../documentation_links/documentation_links';
import './field_editor.less';
import { GetEnabledScriptingLangsProvider, getSupportedScriptingLangs } from '../scripting_langs';
uiModules
.get('kibana', ['colorpicker.module'])
.directive('fieldEditor', function (Private, $sce) {
let fieldFormats = Private(RegistryFieldFormatsProvider);
let Field = Private(IndexPatternsFieldProvider);
let getEnabledScriptingLangs = Private(GetEnabledScriptingLangsProvider);
const fieldTypesByLang = {
painless: ['number', 'string', 'date', 'boolean'],
expression: ['number'],
default: _.keys(Private(IndexPatternsCastMappingTypeProvider).types.byType)
};
return {
restrict: 'E',
template: fieldEditorTemplate,
scope: {
getIndexPattern: '&indexPattern',
getField: '&field'
},
controllerAs: 'editor',
controller: function ($scope, Notifier, kbnUrl, $http, $q) {
let self = this;
let notify = new Notifier({ location: 'Field Editor' });
self.docLinks = docLinks;
getEnabledScriptingLangs().then((langs) => {
self.scriptingLangs = langs;
if (!_.includes(self.scriptingLangs, self.field.lang)) {
self.field.lang = undefined;
}
});
self.indexPattern = $scope.getIndexPattern();
self.field = shadowCopy($scope.getField());
self.formatParams = self.field.format.params();
self.conflictDescriptionsLength = (self.field.conflictDescriptions) ? Object.keys(self.field.conflictDescriptions).length : 0;
// only init on first create
self.creating = !self.indexPattern.fields.byName[self.field.name];
self.selectedFormatId = _.get(self.indexPattern, ['fieldFormatMap', self.field.name, 'type', 'id']);
self.defFormatType = initDefaultFormat();
self.cancel = redirectAway;
self.save = function () {
let indexPattern = self.indexPattern;
let fields = indexPattern.fields;
let field = self.field.toActualField();
fields.remove({ name: field.name });
fields.push(field);
if (!self.selectedFormatId) {
delete indexPattern.fieldFormatMap[field.name];
} else {
indexPattern.fieldFormatMap[field.name] = self.field.format;
}
return indexPattern.save()
.then(function () {
notify.info('Saved Field "' + self.field.name + '"');
redirectAway();
});
};
self.delete = function () {
let indexPattern = self.indexPattern;
let field = self.field;
indexPattern.fields.remove({ name: field.name });
return indexPattern.save()
.then(function () {
notify.info('Deleted Field "' + field.name + '"');
redirectAway();
});
};
self.isSupportedLang = function (lang) {
return _.contains(getSupportedScriptingLangs(), lang);
};
$scope.$watch('editor.selectedFormatId', function (cur, prev) {
let format = self.field.format;
let changedFormat = cur !== prev;
let missingFormat = cur && (!format || format.type.id !== cur);
if (!changedFormat || !missingFormat) return;
// reset to the defaults, but make sure it's an object
self.formatParams = _.assign({}, _.cloneDeep(getFieldFormatType().paramDefaults));
});
$scope.$watch('editor.formatParams', function () {
let FieldFormat = getFieldFormatType();
self.field.format = new FieldFormat(self.formatParams);
}, true);
$scope.$watch('editor.field.type', function (newValue) {
self.defFormatType = initDefaultFormat();
self.fieldFormatTypes = [self.defFormatType].concat(fieldFormats.byFieldType[newValue] || []);
if (_.isUndefined(_.find(self.fieldFormatTypes, {id: self.selectedFormatId}))) {
delete self.selectedFormatId;
}
});
$scope.$watch('editor.field.lang', function (newValue) {
self.fieldTypes = _.get(fieldTypesByLang, newValue, fieldTypesByLang.default);
if (!_.contains(self.fieldTypes, self.field.type)) {
self.field.type = _.first(self.fieldTypes);
}
});
// copy the defined properties of the field to a plain object
// which is mutable, and capture the changed seperately.
function shadowCopy(field) {
let changes = {};
let shadowProps = {
toActualField: {
// bring the shadow copy out of the shadows
value: function toActualField() {
return new Field(self.indexPattern, _.defaults({}, changes, field.$$spec));
}
}
};
Object.getOwnPropertyNames(field).forEach(function (prop) {
let desc = Object.getOwnPropertyDescriptor(field, prop);
shadowProps[prop] = {
enumerable: desc.enumerable,
get: function () {
return _.has(changes, prop) ? changes[prop] : field[prop];
},
set: function (v) {
changes[prop] = v;
}
};
});
return Object.create(null, shadowProps);
}
function redirectAway() {
kbnUrl.changeToRoute(self.indexPattern, self.field.scripted ? 'scriptedFields' : 'indexedFields');
}
function getFieldFormatType() {
if (self.selectedFormatId) return fieldFormats.getType(self.selectedFormatId);
else return fieldFormats.getDefaultType(self.field.type);
}
function initDefaultFormat() {
let def = Object.create(fieldFormats.getDefaultType(self.field.type));
// explicitly set to undefined to prevent inheritting the prototypes id
def.id = undefined;
def.resolvedTitle = def.title;
def.title = '- default - ';
return def;
}
}
};
});