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

[Lens] Make Lens saved object share-capable #111403

Merged
merged 6 commits into from
Sep 13, 2021
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
32 changes: 9 additions & 23 deletions x-pack/plugins/lens/public/persistence/saved_object_store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
* 2.0.
*/

import { SavedObjectsClientContract, SavedObjectsBulkUpdateObject } from 'kibana/public';
import { SavedObjectsClientContract } from 'kibana/public';
import { SavedObjectIndexStore } from './saved_object_store';

describe('LensStore', () => {
function testStore(testId?: string) {
const client = {
create: jest.fn(() => Promise.resolve({ id: testId || 'testid' })),
bulkUpdate: jest.fn(([{ id }]: SavedObjectsBulkUpdateObject[]) =>
Promise.resolve({ savedObjects: [{ id }, { id }] })
),
resolve: jest.fn(),
};

Expand Down Expand Up @@ -81,7 +78,7 @@ describe('LensStore', () => {
});

test('updates and returns a visualization document', async () => {
const { client, store } = testStore();
const { client, store } = testStore('Gandalf');
const doc = await store.save({
savedObjectId: 'Gandalf',
title: 'Even the very wise cannot see all ends.',
Expand All @@ -108,23 +105,11 @@ describe('LensStore', () => {
},
});

expect(client.bulkUpdate).toHaveBeenCalledTimes(1);
expect(client.bulkUpdate).toHaveBeenCalledWith([
{
type: 'lens',
id: 'Gandalf',
references: [],
attributes: {
title: null,
visualizationType: null,
state: null,
},
},
{
type: 'lens',
id: 'Gandalf',
references: [],
attributes: {
expect(client.create).toHaveBeenCalledTimes(1);
expect(client.create.mock.calls).toEqual([
[
'lens',
{
title: 'Even the very wise cannot see all ends.',
visualizationType: 'line',
state: {
Expand All @@ -134,7 +119,8 @@ describe('LensStore', () => {
filters: [],
},
},
},
{ references: [], id: 'Gandalf', overwrite: true },
],
]);
});
});
Expand Down
41 changes: 13 additions & 28 deletions x-pack/plugins/lens/public/persistence/saved_object_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,38 +57,23 @@ export class SavedObjectIndexStore implements SavedObjectStore {
// remove this workaround when SavedObjectAttributes is updated.
const attributes = (rest as unknown) as SavedObjectAttributes;

const result = await (savedObjectId
? this.safeUpdate(savedObjectId, attributes, references)
: this.client.create(DOC_TYPE, attributes, {
references,
}));
const result = await this.client.create(
DOC_TYPE,
attributes,
savedObjectId
? {
references,
overwrite: true,
id: savedObjectId,
}
: {
references,
}
);

return { ...vis, savedObjectId: result.id };
};

// As Lens is using an object to store its attributes, using the update API
// will merge the new attribute object with the old one, not overwriting deleted
// keys. As Lens is using objects as maps in various places, this is a problem because
// deleted subtrees make it back into the object after a load.
// This function fixes this by doing two updates - one to empty out the document setting
// every key to null, and a second one to load the new content.
private async safeUpdate(
savedObjectId: string,
attributes: SavedObjectAttributes,
references: SavedObjectReference[]
) {
const resetAttributes: SavedObjectAttributes = {};
Object.keys(attributes).forEach((key) => {
resetAttributes[key] = null;
});
return (
await this.client.bulkUpdate([
{ type: DOC_TYPE, id: savedObjectId, attributes: resetAttributes, references },
{ type: DOC_TYPE, id: savedObjectId, attributes, references },
])
).savedObjects[1];
}

async load(savedObjectId: string): Promise<ResolvedSimpleSavedObject<LensSavedObjectAttributes>> {
const resolveResult = await this.client.resolve<LensSavedObjectAttributes>(
DOC_TYPE,
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/lens/server/saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export function setupSavedObjects(core: CoreSetup) {
core.savedObjects.registerType({
name: 'lens',
hidden: false,
namespaceType: 'single',
namespaceType: 'multiple-isolated',
convertToMultiNamespaceTypeVersion: '8.0.0',
management: {
icon: 'lensApp',
defaultSearchField: 'title',
Expand Down
Binary file not shown.