mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Refactor loading saved objects (#9406)
* Refactor code that loads saved objects * couple fixes and comments cleanup & comments cleanup * Use es6 classes, make a note about getting rid of the 100 hard limit on results * Address comments * fix linter * lint fixes with { } spacing * Fix linter * fix forgotten merge conflict * and linter
This commit is contained in:
parent
eeb4a7dfeb
commit
1924d28ed8
6 changed files with 141 additions and 271 deletions
|
@ -3,6 +3,7 @@ import Scanner from 'ui/utils/scanner';
|
|||
import 'plugins/kibana/dashboard/services/_saved_dashboard';
|
||||
import uiModules from 'ui/modules';
|
||||
const module = uiModules.get('app/dashboard');
|
||||
import { SavedObjectLoader } from 'ui/courier/saved_object/saved_object_loader';
|
||||
|
||||
// bring in the factory
|
||||
|
||||
|
@ -15,80 +16,6 @@ require('plugins/kibana/management/saved_object_registry').register({
|
|||
});
|
||||
|
||||
// This is the only thing that gets injected into controllers
|
||||
module.service('savedDashboards', function (Promise, SavedDashboard, kbnIndex, es, kbnUrl) {
|
||||
const scanner = new Scanner(es, {
|
||||
index: kbnIndex,
|
||||
type: 'dashboard'
|
||||
});
|
||||
|
||||
this.type = SavedDashboard.type;
|
||||
this.Class = SavedDashboard;
|
||||
|
||||
|
||||
this.loaderProperties = {
|
||||
name: 'dashboards',
|
||||
noun: 'Dashboard',
|
||||
nouns: 'dashboards'
|
||||
};
|
||||
|
||||
// Returns a single dashboard by ID, should be the name of the dashboard
|
||||
this.get = function (id) {
|
||||
// Returns a promise that contains a dashboard which is a subclass of docSource
|
||||
return (new SavedDashboard(id)).init();
|
||||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/dashboard/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, function (id) {
|
||||
return (new SavedDashboard(id)).delete();
|
||||
});
|
||||
};
|
||||
|
||||
this.scanAll = function (queryString, pageSize = 1000) {
|
||||
return scanner.scanAndMap(queryString, {
|
||||
pageSize,
|
||||
docCount: Infinity
|
||||
}, (hit) => this.mapHits(hit));
|
||||
};
|
||||
|
||||
this.mapHits = function (hit) {
|
||||
const source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = this.urlFor(hit._id);
|
||||
return source;
|
||||
};
|
||||
|
||||
this.find = function (searchString, size = 100) {
|
||||
let body;
|
||||
if (searchString) {
|
||||
body = {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND'
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
body = { query: { match_all: {} } };
|
||||
}
|
||||
|
||||
return es.search({
|
||||
index: kbnIndex,
|
||||
type: 'dashboard',
|
||||
body: body,
|
||||
size: size
|
||||
})
|
||||
.then((resp) => {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map((hit) => this.mapHits(hit))
|
||||
};
|
||||
});
|
||||
};
|
||||
module.service('savedDashboards', function (SavedDashboard, kbnIndex, es, kbnUrl) {
|
||||
return new SavedObjectLoader(SavedDashboard, kbnIndex, es, kbnUrl);
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import Scanner from 'ui/utils/scanner';
|
|||
import 'plugins/kibana/discover/saved_searches/_saved_search';
|
||||
import 'ui/notify';
|
||||
import uiModules from 'ui/modules';
|
||||
|
||||
import { SavedObjectLoader } from 'ui/courier/saved_object/saved_object_loader';
|
||||
|
||||
const module = uiModules.get('discover/saved_searches', [
|
||||
'kibana/notify'
|
||||
|
@ -17,82 +17,16 @@ require('plugins/kibana/management/saved_object_registry').register({
|
|||
});
|
||||
|
||||
module.service('savedSearches', function (Promise, config, kbnIndex, es, createNotifier, SavedSearch, kbnUrl) {
|
||||
const scanner = new Scanner(es, {
|
||||
index: kbnIndex,
|
||||
type: 'search'
|
||||
});
|
||||
|
||||
const notify = createNotifier({
|
||||
location: 'Saved Searches'
|
||||
});
|
||||
|
||||
this.type = SavedSearch.type;
|
||||
this.Class = SavedSearch;
|
||||
|
||||
this.loaderProperties = {
|
||||
const savedSearchLoader = new SavedObjectLoader(SavedSearch, kbnIndex, es, kbnUrl);
|
||||
// Customize loader properties since adding an 's' on type doesn't work for type 'search' .
|
||||
savedSearchLoader.loaderProperties = {
|
||||
name: 'searches',
|
||||
noun: 'Saved Search',
|
||||
nouns: 'saved searches'
|
||||
};
|
||||
|
||||
|
||||
this.scanAll = function (queryString, pageSize = 1000) {
|
||||
return scanner.scanAndMap(queryString, {
|
||||
pageSize,
|
||||
docCount: Infinity
|
||||
}, (hit) => this.mapHits(hit));
|
||||
};
|
||||
|
||||
|
||||
this.get = function (id) {
|
||||
return (new SavedSearch(id)).init();
|
||||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
savedSearchLoader.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/discover/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, function (id) {
|
||||
return (new SavedSearch(id)).delete();
|
||||
});
|
||||
};
|
||||
|
||||
this.mapHits = function (hit) {
|
||||
const source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = this.urlFor(hit._id);
|
||||
return source;
|
||||
};
|
||||
|
||||
this.find = function (searchString, size = 100) {
|
||||
let body;
|
||||
if (searchString) {
|
||||
body = {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND'
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
body = { query: { match_all: {} } };
|
||||
}
|
||||
|
||||
return es.search({
|
||||
index: kbnIndex,
|
||||
type: 'search',
|
||||
body: body,
|
||||
size: size
|
||||
})
|
||||
.then((resp) => {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map((hit) => this.mapHits(hit))
|
||||
};
|
||||
});
|
||||
};
|
||||
return savedSearchLoader;
|
||||
});
|
||||
|
|
|
@ -3,6 +3,8 @@ import Scanner from 'ui/utils/scanner';
|
|||
import 'plugins/kibana/visualize/saved_visualizations/_saved_vis';
|
||||
import RegistryVisTypesProvider from 'ui/registry/vis_types';
|
||||
import uiModules from 'ui/modules';
|
||||
import { SavedObjectLoader } from 'ui/courier/saved_object/saved_object_loader';
|
||||
|
||||
const app = uiModules.get('app/visualize');
|
||||
|
||||
|
||||
|
@ -15,48 +17,12 @@ require('plugins/kibana/management/saved_object_registry').register({
|
|||
|
||||
app.service('savedVisualizations', function (Promise, es, kbnIndex, SavedVis, Private, Notifier, kbnUrl) {
|
||||
const visTypes = Private(RegistryVisTypesProvider);
|
||||
|
||||
const scanner = new Scanner(es, {
|
||||
index: kbnIndex,
|
||||
type: 'visualization'
|
||||
});
|
||||
|
||||
const notify = new Notifier({
|
||||
location: 'Saved Visualization Service'
|
||||
});
|
||||
|
||||
this.type = SavedVis.type;
|
||||
this.Class = SavedVis;
|
||||
|
||||
this.loaderProperties = {
|
||||
name: 'visualizations',
|
||||
noun: 'Visualization',
|
||||
nouns: 'visualizations'
|
||||
};
|
||||
|
||||
this.get = function (id) {
|
||||
return (new SavedVis(id)).init();
|
||||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/visualize/edit/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, function (id) {
|
||||
return (new SavedVis(id)).delete();
|
||||
});
|
||||
};
|
||||
|
||||
this.scanAll = function (queryString, pageSize = 1000) {
|
||||
return scanner.scanAndMap(queryString, {
|
||||
pageSize,
|
||||
docCount: Infinity
|
||||
}, (hit) => this.mapHits(hit));
|
||||
};
|
||||
|
||||
this.mapHits = function (hit) {
|
||||
const saveVisualizationLoader = new SavedObjectLoader(SavedVis, kbnIndex, es, kbnUrl);
|
||||
saveVisualizationLoader.mapHits = function (hit) {
|
||||
const source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = this.urlFor(hit._id);
|
||||
|
@ -78,34 +44,9 @@ app.service('savedVisualizations', function (Promise, es, kbnIndex, SavedVis, Pr
|
|||
return source;
|
||||
};
|
||||
|
||||
this.find = function (searchString, size = 100) {
|
||||
let body;
|
||||
if (searchString) {
|
||||
body = {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND',
|
||||
analyze_wildcard: true
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
body = { query: { match_all: {} } };
|
||||
}
|
||||
|
||||
return es.search({
|
||||
index: kbnIndex,
|
||||
type: 'visualization',
|
||||
body: body,
|
||||
size: size
|
||||
})
|
||||
.then((resp) => {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map((hit) => this.mapHits(hit))
|
||||
};
|
||||
});
|
||||
saveVisualizationLoader.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/visualize/edit/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
return saveVisualizationLoader;
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { SavedObjectLoader } from 'ui/courier/saved_object/saved_object_loader';
|
||||
|
||||
define(function (require) {
|
||||
const module = require('ui/modules').get('app/sheet');
|
||||
const _ = require('lodash');
|
||||
|
@ -14,66 +16,17 @@ define(function (require) {
|
|||
|
||||
// This is the only thing that gets injected into controllers
|
||||
module.service('savedSheets', function (Promise, SavedSheet, kbnIndex, es, kbnUrl) {
|
||||
this.type = SavedSheet.type;
|
||||
this.Class = SavedSheet;
|
||||
const savedSheetLoader = new SavedObjectLoader(SavedSheet, kbnIndex, es, kbnUrl);
|
||||
savedSheetLoader.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
this.loaderProperties = {
|
||||
// Customize loader properties since adding an 's' on type doesn't work for type 'timelion-sheet'.
|
||||
savedSheetLoader.loaderProperties = {
|
||||
name: 'timelion-sheet',
|
||||
noun: 'Saved Sheets',
|
||||
nouns: 'saved sheets'
|
||||
};
|
||||
|
||||
// Returns a single sheet by ID, should be the name of the sheet
|
||||
this.get = function (id) {
|
||||
// Returns a promise that contains a sheet which is a subclass of docSource
|
||||
return (new SavedSheet(id)).init();
|
||||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return kbnUrl.eval('#/{{id}}', { id: id });
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, function (id) {
|
||||
return (new SavedSheet(id)).delete();
|
||||
});
|
||||
};
|
||||
|
||||
this.find = function (searchString) {
|
||||
const self = this;
|
||||
let body;
|
||||
if (searchString) {
|
||||
body = {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND'
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
body = { query: { match_all: {} } };
|
||||
}
|
||||
|
||||
return es.search({
|
||||
index: kbnIndex,
|
||||
type: 'timelion-sheet',
|
||||
body: body,
|
||||
size: 1000
|
||||
})
|
||||
.then(function (resp) {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map(function (hit) {
|
||||
const source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = self.urlFor(hit._id);
|
||||
return source;
|
||||
})
|
||||
};
|
||||
});
|
||||
};
|
||||
return savedSheetLoader;
|
||||
});
|
||||
});
|
||||
|
|
104
src/ui/public/courier/saved_object/saved_object_loader.js
Normal file
104
src/ui/public/courier/saved_object/saved_object_loader.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
import _ from 'lodash';
|
||||
import Scanner from 'ui/utils/scanner';
|
||||
import { StringUtils } from 'ui/utils/string_utils';
|
||||
|
||||
export class SavedObjectLoader {
|
||||
constructor(SavedObjectClass, kbnIndex, es, kbnUrl) {
|
||||
this.type = SavedObjectClass.type;
|
||||
this.Class = SavedObjectClass;
|
||||
this.lowercaseType = this.type.toLowerCase();
|
||||
this.kbnIndex = kbnIndex;
|
||||
this.kbnUrl = kbnUrl;
|
||||
this.es = es;
|
||||
|
||||
this.scanner = new Scanner(es, {
|
||||
index: kbnIndex,
|
||||
type: this.lowercaseType
|
||||
});
|
||||
|
||||
this.loaderProperties = {
|
||||
name: `${ this.lowercaseType }s`,
|
||||
noun: StringUtils.upperFirst(this.type),
|
||||
nouns: `${ this.lowercaseType }s`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a saved object by id. Returns a promise that completes when the object finishes
|
||||
* initializing.
|
||||
* @param id
|
||||
* @returns {Promise<SavedObject>}
|
||||
*/
|
||||
get(id) {
|
||||
return (new this.Class(id)).init();
|
||||
}
|
||||
|
||||
urlFor(id) {
|
||||
return this.kbnUrl.eval(`#/${ this.lowercaseType }/{{id}}`, { id: id });
|
||||
}
|
||||
|
||||
delete(ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, (id) => {
|
||||
return (new this.Class(id)).delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates hit._source to contain an id and url field, and returns the updated
|
||||
* source object.
|
||||
* @param hit
|
||||
* @returns {hit._source} The modified hit._source object, with an id and url field.
|
||||
*/
|
||||
mapHits(hit) {
|
||||
const source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = this.urlFor(hit._id);
|
||||
return source;
|
||||
}
|
||||
|
||||
scanAll(queryString, pageSize = 1000) {
|
||||
return this.scanner.scanAndMap(queryString, {
|
||||
pageSize,
|
||||
docCount: Infinity
|
||||
}, (hit) => this.mapHits(hit));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Rather than use a hardcoded limit, implement pagination. See
|
||||
* https://github.com/elastic/kibana/issues/8044 for reference.
|
||||
*
|
||||
* @param searchString
|
||||
* @param size
|
||||
* @returns {Promise}
|
||||
*/
|
||||
find(searchString, size = 100) {
|
||||
let body;
|
||||
if (searchString) {
|
||||
body = {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND'
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
body = { query: { match_all: {} } };
|
||||
}
|
||||
|
||||
return this.es.search({
|
||||
index: this.kbnIndex,
|
||||
type: this.type.toLowerCase(),
|
||||
body,
|
||||
size
|
||||
})
|
||||
.then((resp) => {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map((hit) => this.mapHits(hit))
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
11
src/ui/public/utils/string_utils.js
Normal file
11
src/ui/public/utils/string_utils.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
export class StringUtils {
|
||||
|
||||
/**
|
||||
* Returns a version of the string with the first letter capitalized.
|
||||
* @param str {string}
|
||||
* @returns {string}
|
||||
*/
|
||||
static upperFirst(str) {
|
||||
return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue