Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] Search across spaces (#67644) #71574

Merged
merged 1 commit into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-public.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-public.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-public.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-public.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-public.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-public.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-public](./kibana-plugin-core-public.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-public.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-server.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-server.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-server.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-server.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-server.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-server.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
<b>Signature:</b>

```typescript
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |

<b>Returns:</b>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export declare class SavedObjectsRepository
| [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.delete.md) | | Deletes an object |
| [deleteByNamespace(namespace, options)](./kibana-plugin-core-server.savedobjectsrepository.deletebynamespace.md) | | Deletes all objects from the provided namespace. |
| [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) | | Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[<code>addToNamespaces</code>\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) | | Gets a single object |
| [incrementCounter(type, id, counterFieldName, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increases a counter field by one. Creates the document if one doesn't exist for the given id. |
| [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.update.md) | | Updates an object |
Expand Down
4 changes: 3 additions & 1 deletion src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,7 @@ export interface SavedObjectsCreateOptions {
}

// @public (undocumented)
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
export interface SavedObjectsFindOptions {
// (undocumented)
defaultSearchOperator?: 'AND' | 'OR';
fields?: string[];
Expand All @@ -1294,6 +1294,8 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
id: string;
};
// (undocumented)
namespaces?: string[];
// (undocumented)
page?: number;
// (undocumented)
perPage?: number;
Expand Down
1 change: 1 addition & 0 deletions src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export class SavedObjectsClient {
sortField: 'sort_field',
type: 'type',
filter: 'filter',
namespaces: 'namespaces',
preference: 'preference',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,97 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
"index-pattern",
"search",
],
},
],
],
"results": Array [
Object {
"type": "return",
"value": Promise {},
},
],
}
`);
});

test('omits the `namespaces` property from the export', async () => {
savedObjectsClient.find.mockResolvedValueOnce({
total: 2,
saved_objects: [
{
id: '2',
type: 'search',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [
{
name: 'name',
type: 'index-pattern',
id: '1',
},
],
},
{
id: '1',
type: 'index-pattern',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [],
},
],
per_page: 1,
page: 0,
});
const exportStream = await exportSavedObjectsToStream({
savedObjectsClient,
exportSizeLimit: 500,
types: ['index-pattern', 'search'],
});

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 {
"id": "1",
"name": "name",
"type": "index-pattern",
},
],
"type": "search",
},
Object {
"exportedCount": 2,
"missingRefCount": 0,
"missingReferences": Array [],
},
]
`);
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
Object {
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down Expand Up @@ -257,7 +347,7 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": "foo",
"type": Array [
Expand Down Expand Up @@ -346,7 +436,9 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": "foo",
"namespaces": Array [
"foo",
],
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async function fetchObjectsToExport({
type: types,
search,
perPage: exportSizeLimit,
namespace,
namespaces: namespace ? [namespace] : undefined,
});
if (findResponse.total > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
Expand Down Expand Up @@ -162,10 +162,15 @@ export async function exportSavedObjectsToStream({
exportedObjects = sortObjects(rootObjects);
}

// redact attributes that should not be exported
const redactedObjects = exportedObjects.map<SavedObject<unknown>>(
({ namespaces, ...object }) => object
);

const exportDetails: SavedObjectsExportResultDetails = {
exportedCount: exportedObjects.length,
missingRefCount: missingReferences.length,
missingReferences,
};
return createListStream([...exportedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
return createListStream([...redactedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
}
8 changes: 8 additions & 0 deletions src/core/server/saved_objects/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,18 @@ export const registerFindRoute = (router: IRouter) => {
),
fields: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
filter: schema.maybe(schema.string()),
namespaces: schema.maybe(
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const query = req.query;

const namespaces =
typeof req.query.namespaces === 'string' ? [req.query.namespaces] : req.query.namespaces;

const result = await context.core.savedObjects.client.find({
perPage: query.per_page,
page: query.page,
Expand All @@ -62,6 +69,7 @@ export const registerFindRoute = (router: IRouter) => {
hasReference: query.has_reference,
fields: typeof query.fields === 'string' ? [query.fields] : query.fields,
filter: query.filter,
namespaces,
});

return res.ok({ body: result });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
{
type: 'index-pattern',
Expand All @@ -91,6 +92,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
],
};
Expand Down Expand Up @@ -241,4 +243,38 @@ describe('GET /api/saved_objects/_find', () => {
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as a string', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['foo'],
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as an array', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=default&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['default', 'foo'],
defaultSearchOperator: 'OR',
});
});
});
Loading