* Step 2: Update client code to use resolve() method instead of get() Following sharing Saved Objects developer guide: Step 2 This step demonstrates the changes to update client code to use the new SavedObjectsClient `resolve()` method instead of `get()`. * Step 3 Lens
105 lines
3.3 KiB
TypeScript
105 lines
3.3 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
* 2.0.
|
|
*/
|
|
|
|
import {
|
|
SavedObjectAttributes,
|
|
SavedObjectsClientContract,
|
|
SavedObjectReference,
|
|
ResolvedSimpleSavedObject,
|
|
} from 'kibana/public';
|
|
import { Query } from '../../../../../src/plugins/data/public';
|
|
import { DOC_TYPE, PersistableFilter } from '../../common';
|
|
import { LensSavedObjectAttributes } from '../async_services';
|
|
|
|
export interface Document {
|
|
savedObjectId?: string;
|
|
type?: string;
|
|
visualizationType: string | null;
|
|
title: string;
|
|
description?: string;
|
|
state: {
|
|
datasourceStates: Record<string, unknown>;
|
|
visualization: unknown;
|
|
query: Query;
|
|
globalPalette?: {
|
|
activePaletteId: string;
|
|
state?: unknown;
|
|
};
|
|
filters: PersistableFilter[];
|
|
};
|
|
references: SavedObjectReference[];
|
|
}
|
|
|
|
export interface DocumentSaver {
|
|
save: (vis: Document) => Promise<{ savedObjectId: string }>;
|
|
}
|
|
|
|
export interface DocumentLoader {
|
|
load: (savedObjectId: string) => Promise<ResolvedSimpleSavedObject>;
|
|
}
|
|
|
|
export type SavedObjectStore = DocumentLoader & DocumentSaver;
|
|
|
|
export class SavedObjectIndexStore implements SavedObjectStore {
|
|
private client: SavedObjectsClientContract;
|
|
|
|
constructor(client: SavedObjectsClientContract) {
|
|
this.client = client;
|
|
}
|
|
|
|
save = async (vis: Document) => {
|
|
const { savedObjectId, type, references, ...rest } = vis;
|
|
// TODO: SavedObjectAttributes should support this kind of object,
|
|
// 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,
|
|
}));
|
|
|
|
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,
|
|
savedObjectId
|
|
);
|
|
|
|
if (resolveResult.saved_object.error) {
|
|
throw resolveResult.saved_object.error;
|
|
}
|
|
|
|
return resolveResult;
|
|
}
|
|
}
|