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

[Dashboard First] Genericize Attribute Service #76057

Merged

Conversation

ThomThomson
Copy link
Contributor

@ThomThomson ThomThomson commented Aug 27, 2020

Summary

This PR genericizes the Attribute service by adding an options prop.

The options prop contains:

  1. An optional custom unwrap method that can be used to determine how a savedObject is transformed into the by value input. If left undefined, the attribute service returns the attributes key from the savedObject
  2. An optional custom save method that can be run when the attribute service is wrapping attributes or changing the input to its by reference type. If left undefined, the attribute service will use savedObjectClient.update or savedObjectClient.create. If provided, the attribute service will use the same custom save method in both the update and create cases.

Using the AttributeService

To accept the defaults, you can get the attribute service via:

getAttributeService<MyCoolEmbeddableAttributes>('myCoolEmbeddableType');

Getting an attribute service with custom save, and unwrap methods:

getAttributeService<
  MyCoolEmbeddableAttributes,
  { id: string; attributes: MyCoolEmbeddableAttributes; },    // The by value input is optional and requires a key called 'attributes' which contains the byValueInput
  { id: string; savedObjectId: string; }  // The by reference input type is optional used SavedObjectEmbeddableInput by default
>(this.type, {
  customSaveMethod: (type, attributes, savedObjectId) => { ..... },
  customUnwrapMethod: (savedObject) => { ..... },
});

Checklist

Delete any items that are not applicable to this PR.

For maintainers

@ThomThomson ThomThomson added Feature:Dashboard Dashboard related features Team:Visualizations Visualization editors, elastic-charts and infrastructure v8.0.0 release_note:skip Skip the PR/issue when compiling release notes v7.10.0 labels Aug 27, 2020
@ThomThomson
Copy link
Contributor Author

@elasticmachine merge upstream

@ThomThomson ThomThomson marked this pull request as ready for review August 27, 2020 14:34
@ThomThomson ThomThomson requested a review from a team August 27, 2020 14:34
@ThomThomson ThomThomson requested a review from a team as a code owner August 27, 2020 14:34
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

Copy link
Contributor

@majagrubic majagrubic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting this error when trying to add a book embeddable:

Uncaught (in promise) SyntaxError: Unexpected token u in JSON at position 0
    at JSON.parse (<anonymous>)
    at Object.showSavedObject (visualize_embeddable_factory.tsx:50)
    at saved_object_finder.tsx:53
    at Array.filter (<anonymous>)
    at saved_object_finder.tsx:49

So I couldn't test this. Love addition of unit tests for the attribute service!
Some general thoughts below

const savedItem = await this.savedObjectsClient.create(this.type, newAttributes);
return { savedObjectId: savedItem.id } as RefType;
const savedItem = this.options?.customSaveMethod
? await this.options.customSaveMethod(this.type, newAttributes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes customSaveMethod will take type and attributes parameters by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

customSaveMethod currently uses this signature:

customSaveMethod?: (
  type: string,
  attributes: A,
  savedObjectId?: string
) => Promise<{ id: string }>;

It could easily be changed (and updated in the lens PR as well), but I can't think of a better signature to use.

> {
private embeddableFactory: EmbeddableFactory;
private embeddableFactory?: EmbeddableFactory;
private attributesKey: AttributesKey;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this? It feels like we're trying to be a bit too generic at this point and it's just adding a lot of code branching. Visualize embeddable can wrap its input in attributes, and with having a custom save function, things should work fine. Ie.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this for the case where the only difference between the regular attribute service and the embeddable input that will be using it is the name of the key. This may or may not be the case for Visualize, but I think it's a good feature to support, especially if the 'by value' paradigm will be used this way in many different embeddables. The only new logic this results in is the attribute key line:

this.attributesKey = options?.attributesKey || (ATTRIBUTE_SERVICE_DEFAULT_KEY as AttributesKey);

Afterwards, the logic is all the same, accessing the attributes via:

input[this.attributesKey]

or setting the attributes via:

{ [this.attributesKey]: newAttributes }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually ended up removing the attributesKey to make this PR a little bit simpler. If we experiment with visualize and see that it could be helpful, it would be trivial to re-implement it in a followup PR.

await this.savedObjectsClient.update(this.type, savedObjectId, newAttributes);
return { savedObjectId } as RefType;
if (this.options?.customSaveMethod) {
await this.options.customSaveMethod(this.type, newAttributes, savedObjectId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a customUpdateMethod?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, and I considered it, but made the decision that the customSaveMethod would handle both the update and save cases.

I thought that forgoing this bit of logic in the attribute service

"if you have a custom update method, use that, else if you have a custom save method, use that, else use the default".

... in favor of a little more logic in the custom save method i.e. this little bit of logic from the Lens saved object store:

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

... was a little bit cleaner. This all said, it would be possible to add the custom update method. What do you think works better?

@ThomThomson
Copy link
Contributor Author

I am unable to re-create the error on adding a book embeddable. I double checked creation of a new book and adding it to library, creation of a new book by value, and adding an existing book from the library. Not sure where the problem came from!

@ThomThomson
Copy link
Contributor Author

@elasticmachine merge upstream

Copy link
Member

@ppisljar ppisljar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code LGTM, didn't test out

Copy link
Contributor

@streamich streamich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked on Mac/Chrome, LGTM.

@ThomThomson ThomThomson mentioned this pull request Sep 3, 2020
7 tasks
@ThomThomson
Copy link
Contributor Author

@elasticmachine merge upstream

Copy link
Contributor

@dej611 dej611 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of observations. Tested with Safari 👍 .

…omthomson/kibana into feature/attributeServiceCustomMethods
Copy link
Contributor

@dej611 dej611 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Build metrics

page load bundle size

id value diff baseline
dashboard 709.8KB +1.7KB 708.2KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@ThomThomson ThomThomson merged commit 2606434 into elastic:master Sep 4, 2020
ThomThomson added a commit to ThomThomson/kibana that referenced this pull request Sep 4, 2020
Genericized attribute service, with custom save and unwrap methods and added unit tests.
ThomThomson added a commit that referenced this pull request Sep 4, 2020
Genericized attribute service, with custom save and unwrap methods and added unit tests.
gmmorris added a commit to gmmorris/kibana that referenced this pull request Sep 4, 2020
* master: (47 commits)
  Do not require id & description when creating a logstash pipeline (elastic#76616)
  Remove commented src/core/tsconfig file (elastic#76792)
  Replaced whitelistedHosts with allowedHosts in actions ascii docs (elastic#76731)
  [Dashboard First] Genericize Attribute Service (elastic#76057)
  [ci-metrics] unify distributable file count metrics (elastic#76448)
  [Security Solution][Detections] Handle conflicts on alert status update (elastic#75492)
  [eslint] convert to @typescript-eslint/no-unused-expressions (elastic#76471)
  [DOCS] Add default time range filter to advanced settings (elastic#76414)
  [Security Solution] Refactor NetworkTopNFlow to use Search Strategy (elastic#76249)
  [Dashboard] Update Index Patterns when Child Index Patterns Change (elastic#76356)
  [ML] Add option to Advanced Settings to set default time range filter for AD jobs (elastic#76347)
  Add CSM app to CODEOWNERS (elastic#76793)
  [Security Solution][Exceptions] - Updates exception item find sort field (elastic#76685)
  [Security Solution][Detections][Tech Debt] - Move to using common io-ts types (elastic#75009)
  [Lens] Drag dimension to replace (elastic#75895)
  URI encode the index names we fetch in the fetchIndices lib function. (elastic#76584)
  [Security Solution] Resolver retrieve entity id of documents without field mapped (elastic#76562)
  [Ingest Manager] validate agent route using AJV instead kbn-config-schema (elastic#76546)
  Updated non-dev usages of node-forge (elastic#76699)
  [Ingest Pipelines] Processor forms for processors K-S (elastic#75638)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Dashboard Dashboard related features release_note:skip Skip the PR/issue when compiling release notes Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants