@spalger/kibana
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
221 lines (190 loc) • 7.41 kB
JavaScript
define(function (require) {
var _ = require('lodash');
var angular = require('angular');
var rison = require('ui/utils/rison');
var registry = require('plugins/kibana/settings/saved_object_registry');
var objectViewHTML = require('plugins/kibana/settings/sections/objects/_view.html');
require('ui/routes')
.when('/settings/objects/:service/:id', {
template: objectViewHTML
});
require('ui/modules').get('apps/settings')
.directive('kbnSettingsObjectsView', function (kbnIndex, Notifier) {
return {
restrict: 'E',
controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, es, Private) {
var notify = new Notifier({ location: 'SavedObject view' });
var castMappingType = Private(require('ui/index_patterns/_cast_mapping_type'));
var serviceObj = registry.get($routeParams.service);
var service = $injector.get(serviceObj.service);
/**
* Creates a field definition and pushes it to the memo stack. This function
* is designed to be used in conjunction with _.reduce(). If the
* values is plain object it will recurse through all the keys till it hits
* a string, number or an array.
*
* @param {array} memo The stack of fields
* @param {mixed} value The value of the field
* @param {string} key The key of the field
* @param {object} collection This is a reference the collection being reduced
* @param {array} parents The parent keys to the field
* @returns {array}
*/
var createField = function (memo, val, key, collection, parents) {
if (_.isArray(parents)) {
parents.push(key);
} else {
parents = [key];
}
var field = { type: 'text', name: parents.join('.'), value: val };
if (_.isString(field.value)) {
try {
field.value = angular.toJson(JSON.parse(field.value), true);
field.type = 'json';
} catch (err) {
field.value = field.value;
}
} else if (_.isNumeric(field.value)) {
field.type = 'number';
} else if (_.isArray(field.value)) {
field.type = 'array';
field.value = angular.toJson(field.value, true);
} else if (_.isBoolean(field.value)) {
field.type = 'boolean';
field.value = field.value;
} else if (_.isPlainObject(field.value)) {
// do something recursive
return _.reduce(field.value, _.partialRight(createField, parents), memo);
}
memo.push(field);
// once the field is added to the object you need to pop the parents
// to remove it since we've hit the end of the branch.
parents.pop();
return memo;
};
var readObjectClass = function (fields, Class) {
var fieldMap = _.indexBy(fields, 'name');
_.forOwn(Class.mapping, function (esType, name) {
if (fieldMap[name]) return;
fields.push({
name: name,
type: (function () {
switch (castMappingType(esType)) {
case 'string': return 'text';
case 'number': return 'number';
case 'boolean': return 'boolean';
default: return 'json';
}
}())
});
});
if (Class.searchSource && !fieldMap['kibanaSavedObjectMeta.searchSourceJSON']) {
fields.push({
name: 'kibanaSavedObjectMeta.searchSourceJSON',
type: 'json',
value: '{}'
});
}
};
$scope.notFound = $routeParams.notFound;
$scope.title = service.type;
es.get({
index: kbnIndex,
type: service.type,
id: $routeParams.id
})
.then(function (obj) {
$scope.obj = obj;
$scope.link = service.urlFor(obj._id);
var fields = _.reduce(obj._source, createField, []);
if (service.Class) readObjectClass(fields, service.Class);
$scope.fields = _.sortBy(fields, 'name');
})
.catch(notify.fatal);
// This handles the validation of the Ace Editor. Since we don't have any
// other hooks into the editors to tell us if the content is valid or not
// we need to use the annotations to see if they have any errors. If they
// do then we push the field.name to aceInvalidEditor variable.
// Otherwise we remove it.
var loadedEditors = [];
$scope.aceInvalidEditors = [];
$scope.aceLoaded = function (editor) {
if (_.contains(loadedEditors, editor)) return;
loadedEditors.push(editor);
var session = editor.getSession();
var fieldName = editor.container.id;
session.setTabSize(2);
session.setUseSoftTabs(true);
session.on('changeAnnotation', function () {
var annotations = session.getAnnotations();
if (_.some(annotations, { type: 'error'})) {
if (!_.contains($scope.aceInvalidEditors, fieldName)) {
$scope.aceInvalidEditors.push(fieldName);
}
} else {
$scope.aceInvalidEditors = _.without($scope.aceInvalidEditors, fieldName);
}
if ($rootScope.$$phase) $scope.$apply();
});
};
$scope.cancel = function () {
$window.history.back();
return false;
};
/**
* Deletes an object and sets the notification
* @param {type} name description
* @returns {type} description
*/
$scope.delete = function () {
es.delete({
index: kbnIndex,
type: service.type,
id: $routeParams.id
})
.then(function (resp) {
return redirectHandler('deleted');
})
.catch(notify.fatal);
};
$scope.submit = function () {
var source = _.cloneDeep($scope.obj._source);
_.each($scope.fields, function (field) {
var value = field.value;
if (field.type === 'number') {
value = Number(field.value);
}
if (field.type === 'array') {
value = JSON.parse(field.value);
}
_.set(source, field.name, value);
});
es.index({
index: kbnIndex,
type: service.type,
id: $routeParams.id,
body: source
})
.then(function (resp) {
return redirectHandler('updated');
})
.catch(notify.fatal);
};
function redirectHandler(action) {
return es.indices.refresh({
index: kbnIndex
})
.then(function (resp) {
var msg = 'You successfully ' + action + ' the "' + $scope.obj._source.title + '" ' + $scope.title.toLowerCase() + ' object';
$location.path('/settings/objects').search({
_a: rison.encode({
tab: serviceObj.title
})
});
notify.info(msg);
});
}
}
};
});
});