diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md
index d8ff7b4c9e2ed..36eba99273997 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.exportSizeLimit property
+the maximum number of objects to export.
+
Signature:
```typescript
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md
index 1972cc6634b75..d721fc260eaf8 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.includeReferencesDeep property
+flag to also include all related saved objects in the export response.
+
Signature:
```typescript
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md
index 66f501a0f1433..0f1bd94d01552 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.md
@@ -16,10 +16,11 @@ export interface SavedObjectsExportOptions
| Property | Type | Description |
| --- | --- | --- |
-| [exportSizeLimit](./kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md) | number
| |
-| [includeReferencesDeep](./kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md) | boolean
| |
-| [namespace](./kibana-plugin-server.savedobjectsexportoptions.namespace.md) | string
| |
-| [objects](./kibana-plugin-server.savedobjectsexportoptions.objects.md) | Array<{
id: string;
type: string;
}>
| |
-| [savedObjectsClient](./kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md) | SavedObjectsClientContract
| |
-| [types](./kibana-plugin-server.savedobjectsexportoptions.types.md) | string[]
| |
+| [exportSizeLimit](./kibana-plugin-server.savedobjectsexportoptions.exportsizelimit.md) | number
| the maximum number of objects to export. |
+| [includeReferencesDeep](./kibana-plugin-server.savedobjectsexportoptions.includereferencesdeep.md) | boolean
| flag to also include all related saved objects in the export response. |
+| [namespace](./kibana-plugin-server.savedobjectsexportoptions.namespace.md) | string
| optional namespace to override the namespace used by the savedObjectsClient. |
+| [objects](./kibana-plugin-server.savedobjectsexportoptions.objects.md) | Array<{
id: string;
type: string;
}>
| optional array of objects to export. |
+| [savedObjectsClient](./kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md) | SavedObjectsClientContract
| an instance of the SavedObjectsClient. |
+| [search](./kibana-plugin-server.savedobjectsexportoptions.search.md) | string
| optional query string to filter exported objects. |
+| [types](./kibana-plugin-server.savedobjectsexportoptions.types.md) | string[]
| optional array of saved object types. |
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md
index b5abfba7f6910..1a28cc92e6e7e 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.namespace.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.namespace property
+optional namespace to override the namespace used by the savedObjectsClient.
+
Signature:
```typescript
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md
index 46cb62841d46c..cd32f66c0f81e 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.objects.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.objects property
+optional array of objects to export.
+
Signature:
```typescript
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md
index fc206d0f7e877..1e0dd6c6f164f 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.savedobjectsclient.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.savedObjectsClient property
+an instance of the SavedObjectsClient.
+
Signature:
```typescript
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md
new file mode 100644
index 0000000000000..5e44486ee65e0
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.search.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsExportOptions](./kibana-plugin-server.savedobjectsexportoptions.md) > [search](./kibana-plugin-server.savedobjectsexportoptions.search.md)
+
+## SavedObjectsExportOptions.search property
+
+optional query string to filter exported objects.
+
+Signature:
+
+```typescript
+search?: string;
+```
diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md
index 204402fe355e3..cf1eb676f7ab8 100644
--- a/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md
+++ b/docs/development/core/server/kibana-plugin-server.savedobjectsexportoptions.types.md
@@ -4,6 +4,8 @@
## SavedObjectsExportOptions.types property
+optional array of saved object types.
+
Signature:
```typescript
diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts
index ad2a0e469ddd8..df3bbe7c455e4 100644
--- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts
+++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.test.ts
@@ -96,29 +96,114 @@ describe('getSortedObjectsForExport()', () => {
]
`);
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
- [MockFunction] {
- "calls": Array [
- Array [
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ Object {
+ "namespace": undefined,
+ "perPage": 500,
+ "search": undefined,
+ "sortField": "_id",
+ "sortOrder": "asc",
+ "type": Array [
+ "index-pattern",
+ "search",
+ ],
+ },
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Promise {},
+ },
+ ],
+ }
+ `);
+ });
+
+ test('exports selected types with search string when present', async () => {
+ savedObjectsClient.find.mockResolvedValueOnce({
+ total: 2,
+ saved_objects: [
+ {
+ id: '2',
+ type: 'search',
+ attributes: {},
+ references: [
+ {
+ name: 'name',
+ type: 'index-pattern',
+ id: '1',
+ },
+ ],
+ },
+ {
+ id: '1',
+ type: 'index-pattern',
+ attributes: {},
+ references: [],
+ },
+ ],
+ per_page: 1,
+ page: 0,
+ });
+ const exportStream = await getSortedObjectsForExport({
+ savedObjectsClient,
+ exportSizeLimit: 500,
+ types: ['index-pattern', 'search'],
+ search: 'foo',
+ });
+
+ const response = await readStreamToCompletion(exportStream);
+
+ expect(response).toMatchInlineSnapshot(`
+ Array [
+ Object {
+ "attributes": Object {},
+ "id": "1",
+ "references": Array [],
+ "type": "index-pattern",
+ },
+ Object {
+ "attributes": Object {},
+ "id": "2",
+ "references": Array [
Object {
- "namespace": undefined,
- "perPage": 500,
- "sortField": "_id",
- "sortOrder": "asc",
- "type": Array [
- "index-pattern",
- "search",
- ],
+ "id": "1",
+ "name": "name",
+ "type": "index-pattern",
},
],
- ],
- "results": Array [
- Object {
- "type": "return",
- "value": Promise {},
- },
- ],
- }
+ "type": "search",
+ },
+ ]
`);
+ expect(savedObjectsClient.find).toMatchInlineSnapshot(`
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ Object {
+ "namespace": undefined,
+ "perPage": 500,
+ "search": "foo",
+ "sortField": "_id",
+ "sortOrder": "asc",
+ "type": Array [
+ "index-pattern",
+ "search",
+ ],
+ },
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Promise {},
+ },
+ ],
+ }
+ `);
});
test('exports from the provided namespace when present', async () => {
@@ -179,29 +264,30 @@ describe('getSortedObjectsForExport()', () => {
]
`);
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
- [MockFunction] {
- "calls": Array [
- Array [
- Object {
- "namespace": "foo",
- "perPage": 500,
- "sortField": "_id",
- "sortOrder": "asc",
- "type": Array [
- "index-pattern",
- "search",
- ],
- },
- ],
- ],
- "results": Array [
- Object {
- "type": "return",
- "value": Promise {},
- },
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ Object {
+ "namespace": "foo",
+ "perPage": 500,
+ "search": undefined,
+ "sortField": "_id",
+ "sortOrder": "asc",
+ "type": Array [
+ "index-pattern",
+ "search",
],
- }
- `);
+ },
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Promise {},
+ },
+ ],
+ }
+ `);
});
test('export selected types throws error when exceeding exportSizeLimit', async () => {
@@ -464,4 +550,17 @@ describe('getSortedObjectsForExport()', () => {
`"Either \`type\` or \`objects\` are required."`
);
});
+
+ test('rejects when both objects and search are passed in', () => {
+ const exportOpts = {
+ exportSizeLimit: 1,
+ savedObjectsClient,
+ objects: [{ type: 'index-pattern', id: '1' }],
+ search: 'foo',
+ };
+
+ expect(getSortedObjectsForExport(exportOpts)).rejects.toThrowErrorMatchingInlineSnapshot(
+ `"Can't specify both \\"search\\" and \\"objects\\" properties when exporting"`
+ );
+ });
});
diff --git a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts
index b4e7c2887fd3a..eca8fc0405300 100644
--- a/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts
+++ b/src/core/server/saved_objects/export/get_sorted_objects_for_export.ts
@@ -28,26 +28,38 @@ import { sortObjects } from './sort_objects';
* @public
*/
export interface SavedObjectsExportOptions {
+ /** optional array of saved object types. */
types?: string[];
+ /** optional array of objects to export. */
objects?: Array<{
+ /** the saved object id. */
id: string;
+ /** the saved object type. */
type: string;
}>;
+ /** optional query string to filter exported objects. */
+ search?: string;
+ /** an instance of the SavedObjectsClient. */
savedObjectsClient: SavedObjectsClientContract;
+ /** the maximum number of objects to export. */
exportSizeLimit: number;
+ /** flag to also include all related saved objects in the export response. */
includeReferencesDeep?: boolean;
+ /** optional namespace to override the namespace used by the savedObjectsClient. */
namespace?: string;
}
async function fetchObjectsToExport({
objects,
types,
+ search,
exportSizeLimit,
savedObjectsClient,
namespace,
}: {
objects?: SavedObjectsExportOptions['objects'];
types?: string[];
+ search?: string;
exportSizeLimit: number;
savedObjectsClient: SavedObjectsClientContract;
namespace?: string;
@@ -56,6 +68,9 @@ async function fetchObjectsToExport({
if (objects.length > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
}
+ if (typeof search === 'string') {
+ throw Boom.badRequest(`Can't specify both "search" and "objects" properties when exporting`);
+ }
const bulkGetResult = await savedObjectsClient.bulkGet(objects, { namespace });
const erroredObjects = bulkGetResult.saved_objects.filter(obj => !!obj.error);
if (erroredObjects.length) {
@@ -69,6 +84,7 @@ async function fetchObjectsToExport({
} else if (types && types.length > 0) {
const findResponse = await savedObjectsClient.find({
type: types,
+ search,
sortField: '_id',
sortOrder: 'asc',
perPage: exportSizeLimit,
@@ -86,6 +102,7 @@ async function fetchObjectsToExport({
export async function getSortedObjectsForExport({
types,
objects,
+ search,
savedObjectsClient,
exportSizeLimit,
includeReferencesDeep = false,
@@ -94,6 +111,7 @@ export async function getSortedObjectsForExport({
const objectsToExport = await fetchObjectsToExport({
types,
objects,
+ search,
savedObjectsClient,
exportSizeLimit,
namespace,
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 6451e2b9b7153..79728ecc8fb98 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -820,20 +820,15 @@ export class SavedObjectsErrorHelpers {
// @public
export interface SavedObjectsExportOptions {
- // (undocumented)
exportSizeLimit: number;
- // (undocumented)
includeReferencesDeep?: boolean;
- // (undocumented)
namespace?: string;
- // (undocumented)
objects?: Array<{
id: string;
type: string;
}>;
- // (undocumented)
savedObjectsClient: SavedObjectsClientContract;
- // (undocumented)
+ search?: string;
types?: string[];
}
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
index f7b7f06c2f502..8a7597421600f 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js
@@ -19,6 +19,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
+import { Query } from '@elastic/eui';
import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table';
import { Flyout } from '../components/flyout/';
@@ -44,8 +45,8 @@ jest.mock('../../../lib/fetch_export_objects', () => ({
fetchExportObjects: jest.fn(),
}));
-jest.mock('../../../lib/fetch_export_by_type', () => ({
- fetchExportByType: jest.fn(),
+jest.mock('../../../lib/fetch_export_by_type_and_search', () => ({
+ fetchExportByTypeAndSearch: jest.fn(),
}));
jest.mock('../../../lib/get_saved_object_counts', () => ({
@@ -305,7 +306,7 @@ describe('ObjectsTable', () => {
});
it('should export all', async () => {
- const { fetchExportByType } = require('../../../lib/fetch_export_by_type');
+ const { fetchExportByTypeAndSearch } = require('../../../lib/fetch_export_by_type_and_search');
const { saveAs } = require('@elastic/filesaver');
const component = shallowWithIntl(
{
// Set up mocks
const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' });
- fetchExportByType.mockImplementation(() => blob);
+ fetchExportByTypeAndSearch.mockImplementation(() => blob);
await component.instance().onExportAll();
- expect(fetchExportByType).toHaveBeenCalledWith(POSSIBLE_TYPES, true);
+ expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, undefined, true);
+ expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson');
+ expect(addSuccessMock).toHaveBeenCalledWith({ title: 'Your file is downloading in the background' });
+ });
+
+ it('should export all, accounting for the current search criteria', async () => {
+ const { fetchExportByTypeAndSearch } = require('../../../lib/fetch_export_by_type_and_search');
+ const { saveAs } = require('@elastic/filesaver');
+ const component = shallowWithIntl(
+
+ );
+
+ component.instance().onQueryChange({
+ query: Query.parse('test')
+ });
+
+ // Ensure all promises resolve
+ await new Promise(resolve => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ // Set up mocks
+ const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' });
+ fetchExportByTypeAndSearch.mockImplementation(() => blob);
+
+ await component.instance().onExportAll();
+
+ expect(fetchExportByTypeAndSearch).toHaveBeenCalledWith(POSSIBLE_TYPES, 'test*', true);
expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson');
expect(addSuccessMock).toHaveBeenCalledWith({ title: 'Your file is downloading in the background' });
});
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js
index d0c45f8a7ee08..3670028726f10 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js
@@ -26,8 +26,8 @@ jest.mock('ui/chrome', () => ({
addBasePath: () => ''
}));
-jest.mock('../../../../../lib/fetch_export_by_type', () => ({
- fetchExportByType: jest.fn(),
+jest.mock('../../../../../lib/fetch_export_by_type_and_search', () => ({
+ fetchExportByTypeAndSearch: jest.fn(),
}));
jest.mock('../../../../../lib/fetch_export_objects', () => ({
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js
index 326c577ebe220..3e7e84d75bfe1 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js
@@ -58,7 +58,7 @@ import {
getRelationships,
getSavedObjectLabel,
fetchExportObjects,
- fetchExportByType,
+ fetchExportByTypeAndSearch,
findObjects,
} from '../../lib';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
@@ -303,7 +303,8 @@ class ObjectsTableUI extends Component {
onExportAll = async () => {
const { intl } = this.props;
- const { exportAllSelectedOptions, isIncludeReferencesDeepChecked } = this.state;
+ const { exportAllSelectedOptions, isIncludeReferencesDeepChecked, activeQuery } = this.state;
+ const { queryText } = parseQuery(activeQuery);
const exportTypes = Object.entries(exportAllSelectedOptions).reduce(
(accum, [id, selected]) => {
if (selected) {
@@ -316,7 +317,7 @@ class ObjectsTableUI extends Component {
let blob;
try {
- blob = await fetchExportByType(exportTypes, isIncludeReferencesDeepChecked);
+ blob = await fetchExportByTypeAndSearch(exportTypes, queryText ? `${queryText}*` : undefined, isIncludeReferencesDeepChecked);
} catch (e) {
toastNotifications.addDanger({
title: intl.formatMessage({
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js
similarity index 90%
rename from src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js
rename to src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js
index 71c022b9d3998..788a4635d8dac 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type_and_search.js
@@ -19,12 +19,13 @@
import { kfetch } from 'ui/kfetch';
-export async function fetchExportByType(types, includeReferencesDeep = false) {
+export async function fetchExportByTypeAndSearch(types, search, includeReferencesDeep = false) {
return await kfetch({
method: 'POST',
pathname: '/api/saved_objects/_export',
body: JSON.stringify({
type: types,
+ search,
includeReferencesDeep,
}),
});
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js
index 2818f0d8a6cb4..245812867f1de 100644
--- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js
@@ -17,7 +17,7 @@
* under the License.
*/
-export * from './fetch_export_by_type';
+export * from './fetch_export_by_type_and_search';
export * from './fetch_export_objects';
export * from './in_app_url';
export * from './get_relationships';
diff --git a/src/legacy/server/saved_objects/routes/export.test.ts b/src/legacy/server/saved_objects/routes/export.test.ts
index 6b6e6ac90a48c..491e3a9067611 100644
--- a/src/legacy/server/saved_objects/routes/export.test.ts
+++ b/src/legacy/server/saved_objects/routes/export.test.ts
@@ -62,12 +62,42 @@ describe('POST /api/saved_objects/_export', () => {
jest.resetAllMocks();
});
+ test('does not allow both "search" and "objects" to be specified', async () => {
+ const request = {
+ method: 'POST',
+ url: '/api/saved_objects/_export',
+ payload: {
+ search: 'search',
+ objects: [{ type: 'search', id: 'bar' }],
+ includeReferencesDeep: true,
+ },
+ };
+
+ const { payload, statusCode } = await server.inject(request);
+
+ expect(statusCode).toEqual(400);
+ expect(JSON.parse(payload)).toMatchInlineSnapshot(`
+ Object {
+ "error": "Bad Request",
+ "message": "\\"search\\" must not exist simultaneously with [objects]",
+ "statusCode": 400,
+ "validation": Object {
+ "keys": Array [
+ "value",
+ ],
+ "source": "payload",
+ },
+ }
+ `);
+ });
+
test('formats successful response', async () => {
const request = {
method: 'POST',
url: '/api/saved_objects/_export',
payload: {
type: 'search',
+ search: 'my search string',
includeReferencesDeep: true,
},
};
@@ -101,58 +131,59 @@ describe('POST /api/saved_objects/_export', () => {
expect(headers).toHaveProperty('content-disposition', 'attachment; filename="export.ndjson"');
expect(headers).toHaveProperty('content-type', 'application/ndjson');
expect(objects).toMatchInlineSnapshot(`
-Array [
- Object {
- "attributes": Object {},
- "id": "1",
- "references": Array [],
- "type": "index-pattern",
- },
- Object {
- "attributes": Object {},
- "id": "2",
- "references": Array [
- Object {
- "id": "1",
- "name": "ref_0",
- "type": "index-pattern",
- },
- ],
- "type": "search",
- },
-]
-`);
- expect(getSortedObjectsForExport).toMatchInlineSnapshot(`
-[MockFunction] {
- "calls": Array [
- Array [
- Object {
- "exportSizeLimit": 10000,
- "includeReferencesDeep": true,
- "objects": undefined,
- "savedObjectsClient": Object {
- "bulkCreate": [MockFunction],
- "bulkGet": [MockFunction],
- "create": [MockFunction],
- "delete": [MockFunction],
- "errors": Object {},
- "find": [MockFunction],
- "get": [MockFunction],
- "update": [MockFunction],
+ Array [
+ Object {
+ "attributes": Object {},
+ "id": "1",
+ "references": Array [],
+ "type": "index-pattern",
},
- "types": Array [
- "search",
+ Object {
+ "attributes": Object {},
+ "id": "2",
+ "references": Array [
+ Object {
+ "id": "1",
+ "name": "ref_0",
+ "type": "index-pattern",
+ },
+ ],
+ "type": "search",
+ },
+ ]
+ `);
+ expect(getSortedObjectsForExport).toMatchInlineSnapshot(`
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ Object {
+ "exportSizeLimit": 10000,
+ "includeReferencesDeep": true,
+ "objects": undefined,
+ "savedObjectsClient": Object {
+ "bulkCreate": [MockFunction],
+ "bulkGet": [MockFunction],
+ "create": [MockFunction],
+ "delete": [MockFunction],
+ "errors": Object {},
+ "find": [MockFunction],
+ "get": [MockFunction],
+ "update": [MockFunction],
+ },
+ "search": "my search string",
+ "types": Array [
+ "search",
+ ],
+ },
+ ],
],
- },
- ],
- ],
- "results": Array [
- Object {
- "type": "return",
- "value": Promise {},
- },
- ],
-}
-`);
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Promise {},
+ },
+ ],
+ }
+ `);
});
});
diff --git a/src/legacy/server/saved_objects/routes/export.ts b/src/legacy/server/saved_objects/routes/export.ts
index 32d655531ec74..fc120030a873c 100644
--- a/src/legacy/server/saved_objects/routes/export.ts
+++ b/src/legacy/server/saved_objects/routes/export.ts
@@ -41,6 +41,7 @@ interface ExportRequest extends Hapi.Request {
type: string;
id: string;
}>;
+ search?: string;
includeReferencesDeep: boolean;
};
}
@@ -70,9 +71,11 @@ export const createExportRoute = (
})
.max(server.config().get('savedObjects.maxImportExportSize'))
.optional(),
+ search: Joi.string().optional(),
includeReferencesDeep: Joi.boolean().default(false),
})
.xor('type', 'objects')
+ .nand('search', 'objects')
.default(),
},
async handler(request: ExportRequest, h: Hapi.ResponseToolkit) {
@@ -80,6 +83,7 @@ export const createExportRoute = (
const exportStream = await getSortedObjectsForExport({
savedObjectsClient,
types: request.payload.type,
+ search: request.payload.search,
objects: request.payload.objects,
exportSizeLimit: server.config().get('savedObjects.maxImportExportSize'),
includeReferencesDeep: request.payload.includeReferencesDeep,
diff --git a/test/api_integration/apis/saved_objects/export.js b/test/api_integration/apis/saved_objects/export.js
index 0564c095faa88..e39749aa48159 100644
--- a/test/api_integration/apis/saved_objects/export.js
+++ b/test/api_integration/apis/saved_objects/export.js
@@ -94,6 +94,27 @@ export default function ({ getService }) {
});
});
+ it('should support including dependencies when exporting by type and search', async () => {
+ await supertest
+ .post('/api/saved_objects/_export')
+ .send({
+ includeReferencesDeep: true,
+ type: ['dashboard'],
+ search: 'Requests*'
+ })
+ .expect(200)
+ .then((resp) => {
+ const objects = resp.text.split('\n').map(JSON.parse);
+ expect(objects).to.have.length(3);
+ expect(objects[0]).to.have.property('id', '91200a00-9efd-11e7-acb3-3dab96693fab');
+ expect(objects[0]).to.have.property('type', 'index-pattern');
+ expect(objects[1]).to.have.property('id', 'dd7caf20-9efd-11e7-acb3-3dab96693fab');
+ expect(objects[1]).to.have.property('type', 'visualization');
+ expect(objects[2]).to.have.property('id', 'be3733a0-9efe-11e7-acb3-3dab96693fab');
+ expect(objects[2]).to.have.property('type', 'dashboard');
+ });
+ });
+
it(`should throw error when object doesn't exist`, async () => {
await supertest
.post('/api/saved_objects/_export')