Migrate legacy import/export endpoints (#69474)
* migrate legacy export routes to `legacy_export` plugin * adapt unit tests * remove already dead (already moved) libs
This commit is contained in:
parent
b270321ff3
commit
36b66a802e
|
@ -21,8 +21,6 @@ import Fs from 'fs';
|
|||
import { resolve } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { importApi } from './server/routes/api/import';
|
||||
import { exportApi } from './server/routes/api/export';
|
||||
import { getUiSettingDefaults } from './server/ui_setting_defaults';
|
||||
import { registerCspCollector } from './server/lib/csp_usage_collector';
|
||||
import { injectVars } from './inject_vars';
|
||||
|
@ -91,9 +89,6 @@ export default function (kibana) {
|
|||
|
||||
init: async function (server) {
|
||||
const { usageCollection } = server.newPlatform.setup.plugins;
|
||||
// routes
|
||||
importApi(server);
|
||||
exportApi(server);
|
||||
registerCspCollector(usageCollection, server);
|
||||
server.injectUiAppVars('kibana', () => injectVars(server));
|
||||
},
|
||||
|
|
|
@ -1,645 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { findRelationships } from '../management/saved_objects/relationships';
|
||||
|
||||
function getManagementaMock(savedObjectSchemas) {
|
||||
return {
|
||||
isImportAndExportable(type) {
|
||||
return (
|
||||
!savedObjectSchemas[type] || savedObjectSchemas[type].isImportableAndExportable !== false
|
||||
);
|
||||
},
|
||||
getDefaultSearchField(type) {
|
||||
return savedObjectSchemas[type] && savedObjectSchemas[type].defaultSearchField;
|
||||
},
|
||||
getIcon(type) {
|
||||
return savedObjectSchemas[type] && savedObjectSchemas[type].icon;
|
||||
},
|
||||
getTitle(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getTitle = savedObjectSchemas[type] && savedObjectSchemas[type].getTitle;
|
||||
if (getTitle) {
|
||||
return getTitle(savedObject);
|
||||
}
|
||||
},
|
||||
getEditUrl(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getEditUrl = savedObjectSchemas[type] && savedObjectSchemas[type].getEditUrl;
|
||||
if (getEditUrl) {
|
||||
return getEditUrl(savedObject);
|
||||
}
|
||||
},
|
||||
getInAppUrl(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getInAppUrl = savedObjectSchemas[type] && savedObjectSchemas[type].getInAppUrl;
|
||||
if (getInAppUrl) {
|
||||
return getInAppUrl(savedObject);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const savedObjectsManagement = getManagementaMock({
|
||||
'index-pattern': {
|
||||
icon: 'indexPatternApp',
|
||||
defaultSearchField: 'title',
|
||||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/indexPatterns/patterns/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/management/kibana/indexPatterns/patterns/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'management.kibana.index_patterns',
|
||||
};
|
||||
},
|
||||
},
|
||||
visualization: {
|
||||
icon: 'visualizeApp',
|
||||
defaultSearchField: 'title',
|
||||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedVisualizations/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/visualize#/edit/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
};
|
||||
},
|
||||
},
|
||||
search: {
|
||||
icon: 'search',
|
||||
defaultSearchField: 'title',
|
||||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedSearches/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/discover#//${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
};
|
||||
},
|
||||
},
|
||||
dashboard: {
|
||||
icon: 'dashboardApp',
|
||||
defaultSearchField: 'title',
|
||||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedDashboards/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/kibana#/dashboard/${encodeURIComponent(obj.id)}`,
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('findRelationships', () => {
|
||||
it('should find relationships for dashboards', async () => {
|
||||
const type = 'dashboard';
|
||||
const id = 'foo';
|
||||
const size = 10;
|
||||
|
||||
const savedObjectsClient = {
|
||||
get: () => ({
|
||||
attributes: {
|
||||
panelsJSON: JSON.stringify([
|
||||
{ panelRefName: 'panel_0' },
|
||||
{ panelRefName: 'panel_1' },
|
||||
{ panelRefName: 'panel_2' },
|
||||
]),
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
name: 'panel_1',
|
||||
type: 'visualization',
|
||||
id: '2',
|
||||
},
|
||||
{
|
||||
name: 'panel_2',
|
||||
type: 'visualization',
|
||||
id: '3',
|
||||
},
|
||||
],
|
||||
}),
|
||||
bulkGet: () => ({ saved_objects: [] }),
|
||||
find: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Foo',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'FooBar',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
const result = await findRelationships(type, id, {
|
||||
size,
|
||||
savedObjectsClient,
|
||||
savedObjectsManagement,
|
||||
savedObjectTypes: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
});
|
||||
expect(result).to.eql([
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should find relationships for visualizations', async () => {
|
||||
const type = 'visualization';
|
||||
const id = 'foo';
|
||||
const size = 10;
|
||||
|
||||
const savedObjectsClient = {
|
||||
get: () => ({
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
}),
|
||||
},
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: '1',
|
||||
},
|
||||
],
|
||||
}),
|
||||
bulkGet: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: 'My Index Pattern',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
find: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'dashboard',
|
||||
attributes: {
|
||||
title: 'My Dashboard',
|
||||
panelsJSON: JSON.stringify([
|
||||
{
|
||||
type: 'visualization',
|
||||
id,
|
||||
},
|
||||
{
|
||||
type: 'visualization',
|
||||
id: 'foobar',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'dashboard',
|
||||
attributes: {
|
||||
title: 'Your Dashboard',
|
||||
panelsJSON: JSON.stringify([
|
||||
{
|
||||
type: 'visualization',
|
||||
id,
|
||||
},
|
||||
{
|
||||
type: 'visualization',
|
||||
id: 'foobar',
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
|
||||
const result = await findRelationships(type, id, {
|
||||
size,
|
||||
savedObjectsClient,
|
||||
savedObjectsManagement,
|
||||
savedObjectTypes: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
});
|
||||
expect(result).to.eql([
|
||||
{
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
relationship: 'child',
|
||||
meta: {
|
||||
icon: 'indexPatternApp',
|
||||
title: 'My Index Pattern',
|
||||
editUrl: '/management/kibana/indexPatterns/patterns/1',
|
||||
inAppUrl: {
|
||||
path: '/app/management/kibana/indexPatterns/patterns/1',
|
||||
uiCapabilitiesPath: 'management.kibana.index_patterns',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'dashboard',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'dashboardApp',
|
||||
title: 'My Dashboard',
|
||||
editUrl: '/management/kibana/objects/savedDashboards/1',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/dashboard/1',
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'dashboard',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'dashboardApp',
|
||||
title: 'Your Dashboard',
|
||||
editUrl: '/management/kibana/objects/savedDashboards/2',
|
||||
inAppUrl: {
|
||||
path: '/app/kibana#/dashboard/2',
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should find relationships for saved searches', async () => {
|
||||
const type = 'search';
|
||||
const id = 'foo';
|
||||
const size = 10;
|
||||
|
||||
const savedObjectsClient = {
|
||||
get: () => ({
|
||||
id: '1',
|
||||
type: 'search',
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
}),
|
||||
},
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: '1',
|
||||
},
|
||||
],
|
||||
}),
|
||||
bulkGet: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: 'My Index Pattern',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
find: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Foo',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'FooBar',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
|
||||
const result = await findRelationships(type, id, {
|
||||
size,
|
||||
savedObjectsClient,
|
||||
savedObjectsManagement,
|
||||
savedObjectTypes: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
});
|
||||
expect(result).to.eql([
|
||||
{
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
relationship: 'child',
|
||||
meta: {
|
||||
icon: 'indexPatternApp',
|
||||
title: 'My Index Pattern',
|
||||
editUrl: '/management/kibana/indexPatterns/patterns/1',
|
||||
inAppUrl: {
|
||||
path: '/app/management/kibana/indexPatterns/patterns/1',
|
||||
uiCapabilitiesPath: 'management.kibana.index_patterns',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should find relationships for index patterns', async () => {
|
||||
const type = 'index-pattern';
|
||||
const id = 'foo';
|
||||
const size = 10;
|
||||
|
||||
const savedObjectsClient = {
|
||||
get: () => ({
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: 'My Index Pattern',
|
||||
},
|
||||
}),
|
||||
find: () => ({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Foo',
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
index: 'foo',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'Bar',
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
index: 'foo',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
title: 'FooBar',
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
index: 'foo2',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'search',
|
||||
attributes: {
|
||||
title: 'My Saved Search',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
|
||||
const result = await findRelationships(type, id, {
|
||||
size,
|
||||
savedObjectsClient,
|
||||
savedObjectsManagement,
|
||||
savedObjectTypes: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
});
|
||||
expect(result).to.eql([
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Foo',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/1',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/1',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Bar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/2',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/2',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'visualization',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'FooBar',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/3',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/3',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'search',
|
||||
relationship: 'parent',
|
||||
meta: {
|
||||
icon: 'search',
|
||||
title: 'My Saved Search',
|
||||
editUrl: '/management/kibana/objects/savedSearches/1',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#//1',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an empty object for non related objects', async () => {
|
||||
const type = 'invalid';
|
||||
const id = 'foo';
|
||||
const size = 10;
|
||||
|
||||
const savedObjectsClient = {
|
||||
get: () => ({
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: 'My Index Pattern',
|
||||
},
|
||||
references: [],
|
||||
}),
|
||||
find: () => ({ saved_objects: [] }),
|
||||
};
|
||||
|
||||
const result = await findRelationships(type, id, {
|
||||
size,
|
||||
savedObjectsClient,
|
||||
savedObjectsManagement,
|
||||
savedObjectTypes: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
});
|
||||
expect(result).to.eql({});
|
||||
});
|
||||
});
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { importDashboards } from './import_dashboards';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('importDashboards(req)', () => {
|
||||
let req;
|
||||
let bulkCreateStub;
|
||||
beforeEach(() => {
|
||||
bulkCreateStub = sinon.stub().returns(Promise.resolve({ saved_objects: [] }));
|
||||
req = {
|
||||
query: {},
|
||||
payload: {
|
||||
version: '6.0.0',
|
||||
objects: [
|
||||
{ id: 'dashboard-01', type: 'dashboard', attributes: { panelJSON: '{}' } },
|
||||
{ id: 'panel-01', type: 'visualization', attributes: { visState: '{}' } },
|
||||
],
|
||||
},
|
||||
getSavedObjectsClient() {
|
||||
return {
|
||||
bulkCreate: bulkCreateStub,
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
test('should call bulkCreate with each asset', () => {
|
||||
return importDashboards(req).then(() => {
|
||||
expect(bulkCreateStub.calledOnce).toEqual(true);
|
||||
expect(bulkCreateStub.args[0][0]).toEqual([
|
||||
{
|
||||
id: 'dashboard-01',
|
||||
type: 'dashboard',
|
||||
attributes: { panelJSON: '{}' },
|
||||
migrationVersion: {},
|
||||
},
|
||||
{
|
||||
id: 'panel-01',
|
||||
type: 'visualization',
|
||||
attributes: { visState: '{}' },
|
||||
migrationVersion: {},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should call bulkCreate with overwrite true if force is truthy', () => {
|
||||
req.query = { force: 'true' };
|
||||
return importDashboards(req).then(() => {
|
||||
expect(bulkCreateStub.calledOnce).toEqual(true);
|
||||
expect(bulkCreateStub.args[0][1]).toEqual({ overwrite: true });
|
||||
});
|
||||
});
|
||||
|
||||
test('should exclude types based on exclude argument', () => {
|
||||
req.query = { exclude: 'visualization' };
|
||||
return importDashboards(req).then(() => {
|
||||
expect(bulkCreateStub.calledOnce).toEqual(true);
|
||||
expect(bulkCreateStub.args[0][0]).toEqual([
|
||||
{
|
||||
id: 'dashboard-01',
|
||||
type: 'dashboard',
|
||||
attributes: { panelJSON: '{}' },
|
||||
migrationVersion: {},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { injectMetaAttributes } from './inject_meta_attributes';
|
||||
|
||||
function getManagementMock(savedObjectSchemas) {
|
||||
return {
|
||||
isImportAndExportable(type) {
|
||||
return (
|
||||
!savedObjectSchemas[type] || savedObjectSchemas[type].isImportableAndExportable !== false
|
||||
);
|
||||
},
|
||||
getDefaultSearchField(type) {
|
||||
return savedObjectSchemas[type] && savedObjectSchemas[type].defaultSearchField;
|
||||
},
|
||||
getIcon(type) {
|
||||
return savedObjectSchemas[type] && savedObjectSchemas[type].icon;
|
||||
},
|
||||
getTitle(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getTitle = savedObjectSchemas[type] && savedObjectSchemas[type].getTitle;
|
||||
if (getTitle) {
|
||||
return getTitle(savedObject);
|
||||
}
|
||||
},
|
||||
getEditUrl(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getEditUrl = savedObjectSchemas[type] && savedObjectSchemas[type].getEditUrl;
|
||||
if (getEditUrl) {
|
||||
return getEditUrl(savedObject);
|
||||
}
|
||||
},
|
||||
getInAppUrl(savedObject) {
|
||||
const { type } = savedObject;
|
||||
const getInAppUrl = savedObjectSchemas[type] && savedObjectSchemas[type].getInAppUrl;
|
||||
if (getInAppUrl) {
|
||||
return getInAppUrl(savedObject);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('works when no schema is defined for the type', () => {
|
||||
const savedObject = { type: 'a' };
|
||||
const savedObjectsManagement = getManagementMock({});
|
||||
const result = injectMetaAttributes(savedObject, savedObjectsManagement);
|
||||
expect(result).toEqual({ type: 'a', meta: {} });
|
||||
});
|
||||
|
||||
test('inject icon into meta attribute', () => {
|
||||
const savedObject = {
|
||||
type: 'a',
|
||||
};
|
||||
const savedObjectsManagement = getManagementMock({
|
||||
a: {
|
||||
icon: 'my-icon',
|
||||
},
|
||||
});
|
||||
const result = injectMetaAttributes(savedObject, savedObjectsManagement);
|
||||
expect(result).toEqual({
|
||||
type: 'a',
|
||||
meta: {
|
||||
icon: 'my-icon',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('injects title into meta attribute', () => {
|
||||
const savedObject = {
|
||||
type: 'a',
|
||||
};
|
||||
const savedObjectsManagement = getManagementMock({
|
||||
a: {
|
||||
getTitle() {
|
||||
return 'my-title';
|
||||
},
|
||||
},
|
||||
});
|
||||
const result = injectMetaAttributes(savedObject, savedObjectsManagement);
|
||||
expect(result).toEqual({
|
||||
type: 'a',
|
||||
meta: {
|
||||
title: 'my-title',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('injects editUrl into meta attribute', () => {
|
||||
const savedObject = {
|
||||
type: 'a',
|
||||
};
|
||||
const savedObjectsManagement = getManagementMock({
|
||||
a: {
|
||||
getEditUrl() {
|
||||
return 'my-edit-url';
|
||||
},
|
||||
},
|
||||
});
|
||||
const result = injectMetaAttributes(savedObject, savedObjectsManagement);
|
||||
expect(result).toEqual({
|
||||
type: 'a',
|
||||
meta: {
|
||||
editUrl: 'my-edit-url',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('injects inAppUrl meta attribute', () => {
|
||||
const savedObject = {
|
||||
type: 'a',
|
||||
};
|
||||
const savedObjectsManagement = getManagementMock({
|
||||
a: {
|
||||
getInAppUrl() {
|
||||
return {
|
||||
path: 'my-in-app-url',
|
||||
uiCapabilitiesPath: 'ui.path',
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
const result = injectMetaAttributes(savedObject, savedObjectsManagement);
|
||||
expect(result).toEqual({
|
||||
type: 'a',
|
||||
meta: {
|
||||
inAppUrl: {
|
||||
path: 'my-in-app-url',
|
||||
uiCapabilitiesPath: 'ui.path',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { pick } from 'lodash';
|
||||
import { injectMetaAttributes } from './inject_meta_attributes';
|
||||
|
||||
export async function findRelationships(type, id, options = {}) {
|
||||
const { size, savedObjectsClient, savedObjectTypes, savedObjectsManagement } = options;
|
||||
|
||||
const { references = [] } = await savedObjectsClient.get(type, id);
|
||||
|
||||
// Use a map to avoid duplicates, it does happen but have a different "name" in the reference
|
||||
const referencedToBulkGetOpts = new Map(
|
||||
references.map(({ type, id }) => [`${type}:${id}`, { id, type }])
|
||||
);
|
||||
|
||||
const [referencedObjects, referencedResponse] = await Promise.all([
|
||||
referencedToBulkGetOpts.size > 0
|
||||
? savedObjectsClient.bulkGet([...referencedToBulkGetOpts.values()])
|
||||
: Promise.resolve({ saved_objects: [] }),
|
||||
savedObjectsClient.find({
|
||||
hasReference: { type, id },
|
||||
perPage: size,
|
||||
type: savedObjectTypes,
|
||||
}),
|
||||
]);
|
||||
|
||||
return [].concat(
|
||||
referencedObjects.saved_objects
|
||||
.map((obj) => injectMetaAttributes(obj, savedObjectsManagement))
|
||||
.map(extractCommonProperties)
|
||||
.map((obj) => ({
|
||||
...obj,
|
||||
relationship: 'child',
|
||||
})),
|
||||
referencedResponse.saved_objects
|
||||
.map((obj) => injectMetaAttributes(obj, savedObjectsManagement))
|
||||
.map(extractCommonProperties)
|
||||
.map((obj) => ({
|
||||
...obj,
|
||||
relationship: 'parent',
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
function extractCommonProperties(savedObject) {
|
||||
return pick(savedObject, ['id', 'type', 'meta']);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import moment from 'moment';
|
||||
|
||||
import { exportDashboards } from '../../../lib/export/export_dashboards';
|
||||
|
||||
export function exportApi(server) {
|
||||
server.route({
|
||||
path: '/api/kibana/dashboards/export',
|
||||
config: {
|
||||
validate: {
|
||||
query: Joi.object().keys({
|
||||
dashboard: Joi.alternatives()
|
||||
.try(Joi.string(), Joi.array().items(Joi.string()))
|
||||
.required(),
|
||||
}),
|
||||
},
|
||||
tags: ['api'],
|
||||
},
|
||||
method: ['GET'],
|
||||
handler: async (req, h) => {
|
||||
const currentDate = moment.utc();
|
||||
return exportDashboards(req).then((resp) => {
|
||||
const json = JSON.stringify(resp, null, ' ');
|
||||
const filename = `kibana-dashboards.${currentDate.format('YYYY-MM-DD-HH-mm-ss')}.json`;
|
||||
return h
|
||||
.response(json)
|
||||
.header('Content-Disposition', `attachment; filename="${filename}"`)
|
||||
.header('Content-Type', 'application/json')
|
||||
.header('Content-Length', Buffer.byteLength(json, 'utf8'));
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
6
src/plugins/legacy_export/kibana.json
Normal file
6
src/plugins/legacy_export/kibana.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"id": "legacyExport",
|
||||
"version": "kibana",
|
||||
"server": true,
|
||||
"ui": false
|
||||
}
|
|
@ -17,17 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export function injectMetaAttributes(savedObject, savedObjectsManagement) {
|
||||
const result = {
|
||||
...savedObject,
|
||||
meta: savedObject.meta || {},
|
||||
};
|
||||
import { PluginInitializer } from 'src/core/server';
|
||||
import { LegacyExportPlugin } from './plugin';
|
||||
|
||||
// Add extra meta information
|
||||
result.meta.icon = savedObjectsManagement.getIcon(savedObject.type);
|
||||
result.meta.title = savedObjectsManagement.getTitle(savedObject);
|
||||
result.meta.editUrl = savedObjectsManagement.getEditUrl(savedObject);
|
||||
result.meta.inAppUrl = savedObjectsManagement.getInAppUrl(savedObject);
|
||||
|
||||
return result;
|
||||
}
|
||||
export const plugin: PluginInitializer<{}, {}> = (context) => new LegacyExportPlugin(context);
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
import { SavedObject, SavedObjectAttributes } from 'src/core/server';
|
||||
import { savedObjectsClientMock } from '../../../../../core/server/mocks';
|
||||
import { collectReferencesDeep } from './collect_references_deep';
|
||||
import { savedObjectsClientMock } from '../../../../../../core/server/mocks';
|
||||
|
||||
const data: Array<SavedObject<SavedObjectAttributes>> = [
|
||||
{
|
|
@ -29,7 +29,7 @@ interface ObjectsToCollect {
|
|||
export async function collectReferencesDeep(
|
||||
savedObjectClient: SavedObjectsClientContract,
|
||||
objects: ObjectsToCollect[]
|
||||
) {
|
||||
): Promise<SavedObject[]> {
|
||||
let result: SavedObject[] = [];
|
||||
const queue = [...objects];
|
||||
while (queue.length !== 0) {
|
|
@ -17,19 +17,19 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SavedObjectsClientContract } from 'src/core/server';
|
||||
import { collectReferencesDeep } from './collect_references_deep';
|
||||
|
||||
export async function exportDashboards(req) {
|
||||
const ids = _.flatten([req.query.dashboard]);
|
||||
const config = req.server.config();
|
||||
|
||||
const savedObjectsClient = req.getSavedObjectsClient();
|
||||
export async function exportDashboards(
|
||||
ids: string[],
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
kibanaVersion: string
|
||||
) {
|
||||
const objectsToExport = ids.map((id) => ({ id, type: 'dashboard' }));
|
||||
|
||||
const objects = await collectReferencesDeep(savedObjectsClient, objectsToExport);
|
||||
return {
|
||||
version: config.get('pkg.version'),
|
||||
version: kibanaVersion,
|
||||
objects,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { savedObjectsClientMock } from '../../../../../core/server/mocks';
|
||||
import { SavedObject } from '../../../../../core/server';
|
||||
import { importDashboards } from './import_dashboards';
|
||||
|
||||
describe('importDashboards(req)', () => {
|
||||
let savedObjectClient: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
let importedObjects: SavedObject[];
|
||||
|
||||
beforeEach(() => {
|
||||
savedObjectClient = savedObjectsClientMock.create();
|
||||
savedObjectClient.bulkCreate.mockResolvedValue({ saved_objects: [] });
|
||||
|
||||
importedObjects = [
|
||||
{ id: 'dashboard-01', type: 'dashboard', attributes: { panelJSON: '{}' }, references: [] },
|
||||
{ id: 'panel-01', type: 'visualization', attributes: { visState: '{}' }, references: [] },
|
||||
];
|
||||
});
|
||||
|
||||
test('should call bulkCreate with each asset', async () => {
|
||||
await importDashboards(savedObjectClient, importedObjects, { overwrite: false, exclude: [] });
|
||||
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
id: 'dashboard-01',
|
||||
type: 'dashboard',
|
||||
attributes: { panelJSON: '{}' },
|
||||
references: [],
|
||||
migrationVersion: {},
|
||||
},
|
||||
{
|
||||
id: 'panel-01',
|
||||
type: 'visualization',
|
||||
attributes: { visState: '{}' },
|
||||
references: [],
|
||||
migrationVersion: {},
|
||||
},
|
||||
],
|
||||
{ overwrite: false }
|
||||
);
|
||||
});
|
||||
|
||||
test('should call bulkCreate with overwrite true if force is truthy', async () => {
|
||||
await importDashboards(savedObjectClient, importedObjects, { overwrite: true, exclude: [] });
|
||||
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledWith(expect.any(Array), {
|
||||
overwrite: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('should exclude types based on exclude argument', async () => {
|
||||
await importDashboards(savedObjectClient, importedObjects, {
|
||||
overwrite: false,
|
||||
exclude: ['visualization'],
|
||||
});
|
||||
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectClient.bulkCreate).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
id: 'dashboard-01',
|
||||
type: 'dashboard',
|
||||
attributes: { panelJSON: '{}' },
|
||||
references: [],
|
||||
migrationVersion: {},
|
||||
},
|
||||
],
|
||||
{ overwrite: false }
|
||||
);
|
||||
});
|
||||
});
|
|
@ -17,21 +17,19 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { flatten } from 'lodash';
|
||||
|
||||
export async function importDashboards(req) {
|
||||
const { payload } = req;
|
||||
const overwrite = 'force' in req.query && req.query.force !== false;
|
||||
const exclude = flatten([req.query.exclude]);
|
||||
|
||||
const savedObjectsClient = req.getSavedObjectsClient();
|
||||
import { SavedObject, SavedObjectsClientContract } from 'src/core/server';
|
||||
|
||||
export async function importDashboards(
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
objects: SavedObject[],
|
||||
{ overwrite, exclude }: { overwrite: boolean; exclude: string[] }
|
||||
) {
|
||||
// The server assumes that documents with no migrationVersion are up to date.
|
||||
// That assumption enables Kibana and other API consumers to not have to build
|
||||
// up migrationVersion prior to creating new objects. But it means that imports
|
||||
// need to set migrationVersion to something other than undefined, so that imported
|
||||
// docs are not seen as automatically up-to-date.
|
||||
const docs = payload.objects
|
||||
const docs = objects
|
||||
.filter((item) => !exclude.includes(item.type))
|
||||
.map((doc) => ({ ...doc, migrationVersion: doc.migrationVersion || {} }));
|
||||
|
21
src/plugins/legacy_export/server/lib/index.ts
Normal file
21
src/plugins/legacy_export/server/lib/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
export { exportDashboards } from './export/export_dashboards';
|
||||
export { importDashboards } from './import/import_dashboards';
|
|
@ -17,29 +17,26 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { importDashboards } from '../../../lib/import/import_dashboards';
|
||||
import { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server';
|
||||
import { registerRoutes } from './routes';
|
||||
|
||||
export function importApi(server) {
|
||||
server.route({
|
||||
path: '/api/kibana/dashboards/import',
|
||||
method: ['POST'],
|
||||
config: {
|
||||
validate: {
|
||||
payload: Joi.object().keys({
|
||||
objects: Joi.array(),
|
||||
version: Joi.string(),
|
||||
}),
|
||||
query: Joi.object().keys({
|
||||
force: Joi.boolean().default(false),
|
||||
exclude: [Joi.string(), Joi.array().items(Joi.string())],
|
||||
}),
|
||||
},
|
||||
tags: ['api'],
|
||||
},
|
||||
export class LegacyExportPlugin implements Plugin<{}, {}> {
|
||||
private readonly kibanaVersion: string;
|
||||
|
||||
handler: async (req) => {
|
||||
return await importDashboards(req);
|
||||
},
|
||||
});
|
||||
constructor(context: PluginInitializerContext) {
|
||||
this.kibanaVersion = context.env.packageInfo.version;
|
||||
}
|
||||
|
||||
public setup({ http }: CoreSetup) {
|
||||
const router = http.createRouter();
|
||||
registerRoutes(router, this.kibanaVersion);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start() {
|
||||
return {};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
56
src/plugins/legacy_export/server/routes/export.ts
Normal file
56
src/plugins/legacy_export/server/routes/export.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from 'src/core/server';
|
||||
import { exportDashboards } from '../lib';
|
||||
|
||||
export const registerExportRoute = (router: IRouter, kibanaVersion: string) => {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/kibana/dashboards/export',
|
||||
validate: {
|
||||
query: schema.object({
|
||||
dashboard: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
tags: ['api'],
|
||||
},
|
||||
},
|
||||
async (ctx, req, res) => {
|
||||
const ids = Array.isArray(req.query.dashboard) ? req.query.dashboard : [req.query.dashboard];
|
||||
const { client } = ctx.core.savedObjects;
|
||||
|
||||
const exported = await exportDashboards(ids, client, kibanaVersion);
|
||||
const filename = `kibana-dashboards.${moment.utc().format('YYYY-MM-DD-HH-mm-ss')}.json`;
|
||||
const body = JSON.stringify(exported, null, ' ');
|
||||
|
||||
return res.ok({
|
||||
body,
|
||||
headers: {
|
||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': `${Buffer.byteLength(body, 'utf8')}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
57
src/plugins/legacy_export/server/routes/import.ts
Normal file
57
src/plugins/legacy_export/server/routes/import.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter, SavedObject } from 'src/core/server';
|
||||
import { importDashboards } from '../lib';
|
||||
|
||||
export const registerImportRoute = (router: IRouter) => {
|
||||
router.post(
|
||||
{
|
||||
path: '/api/kibana/dashboards/import',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
objects: schema.arrayOf(schema.recordOf(schema.string(), schema.any())),
|
||||
version: schema.string(),
|
||||
}),
|
||||
query: schema.object({
|
||||
force: schema.boolean({ defaultValue: false }),
|
||||
exclude: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], {
|
||||
defaultValue: [],
|
||||
}),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
tags: ['api'],
|
||||
},
|
||||
},
|
||||
async (ctx, req, res) => {
|
||||
const { client } = ctx.core.savedObjects;
|
||||
const objects = req.body.objects as SavedObject[];
|
||||
const { force, exclude } = req.query;
|
||||
const result = await importDashboards(client, objects, {
|
||||
overwrite: force,
|
||||
exclude: Array.isArray(exclude) ? exclude : [exclude],
|
||||
});
|
||||
return res.ok({
|
||||
body: result,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
27
src/plugins/legacy_export/server/routes/index.ts
Normal file
27
src/plugins/legacy_export/server/routes/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. 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.
|
||||
*/
|
||||
|
||||
import { IRouter } from 'src/core/server';
|
||||
import { registerImportRoute } from './import';
|
||||
import { registerExportRoute } from './export';
|
||||
|
||||
export const registerRoutes = (router: IRouter, kibanaVersion: string) => {
|
||||
registerExportRoute(router, kibanaVersion);
|
||||
registerImportRoute(router);
|
||||
};
|
Loading…
Reference in a new issue