Skip to content

Conversation

@mattkime
Copy link
Contributor

@mattkime mattkime commented Jun 13, 2020

Summary

  • Use async interface for uiSettings - provide public and server shims to use common interface. Pre-cache values for sync calls such as field formatters.
  • IndexPatternsApiClient - shim, passing in as argument - mocked on server since client implementation makes http calls. Will throw error if used on server. used for updating field list _get_fields_for_wildcard Will fully implement later.
  • SavedObjects client shim - Works with the server's SavedObject rather than SimpleSavedObject
  • plugin functional test verifies functionality

Checklist

Delete any items that are not applicable to this PR.

For maintainers

@mattkime mattkime requested review from a team as code owners June 27, 2020 01:54
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-arch (Team:AppArch)

@mattkime mattkime added the release_note:skip Skip the PR/issue when compiling release notes label Jun 27, 2020
@elastic elastic deleted a comment from kibanamachine Jun 27, 2020
@mattkime
Copy link
Contributor Author

@elasticmachine merge upstream

Copy link
Contributor

@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

async specToIndexPattern(spec: IndexPatternSpec) {
const shortDotsEnable = await this.config.get(UI_SETTINGS.SHORT_DOTS_ENABLE);
const metaFields = await this.config.get(UI_SETTINGS.META_FIELDS);
const uiSettingsValues = await this.config.getAll();
Copy link
Contributor

Choose a reason for hiding this comment

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

i guess shortDotsEnable and metaFields are also part of getAll ?
i would prefer not doing getAll at all and rather identify the specific settings that are required if possible ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently FieldFormatters can access any uiSetting. getAll is used to support them. We should look at refactoring FieldFormatters so they're not dependent on being passed a dependency like this.

Copy link
Member

Choose a reason for hiding this comment

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

i would prefer not doing getAll at all and rather identify the specific settings that are required if possible ?

We should look at refactoring FieldFormatters so they're not dependent on being passed a dependency like this.

++ To both of these ideas. Ideally we would only include the subset of uiSettings which are actually needed.

One thing I'm still not sure about is whether we are going to run into issues caching the uiSettingsValues like this. What happens if someone updates a uiSetting (on the client) after we have already cached the settings with getAll? Now they will be getting an outdated value. Whereas in the previous implementation (with getConfig) we were calling uiSettings.get each time, which guaranteed you would always be getting the latest value.

Looking at index_pattern.ts it seems getConfig is only called once in the constructor which means this wouldn't be an issue anywhere except in deserializeFieldFormatMap where the cached values are passed to a new FieldFormat instance -- so does this mean that the field formats will all now have a cached version of the ui settings which could potentially be stale?

I'm wondering if instead this cache should be handled internally in the ui settings client/public wrapper, and then subscribe to the uiSettings.getSaved$ observable which (I believe) will broadcast an update any time a setting is updated. This could then be used to update the cached retrieved with getAll:

class UiSettingsPublicToCommon {
  constructor() {
    this.cache = core.uiSettings.getAll();
    this.subscription = core.uiSettings.getSaved$.subscribe(({ key, newValue, oldValue }) => {
      this.cache[key] = newValue;
    });
  }
  get() {
    return Promise.resolve(this.cache[val]);
  }
  stop() {
    // cleanup which would need to be called in the plugin's `stop` 
    this.subscription.unsubscribe();
  }
}

...omit(simpleSavedObject, '_version'),
});

export class SavedObjectsClientPublicToCommon implements SavedObjectsClientCommon {
Copy link
Contributor

Choose a reason for hiding this comment

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

have you checked with platform team about this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, they've confirmed that its the correct strategy and that more complete parity between APIs would take a fair amount more work.


const indexPatternCache = await getIndexPatternService().getCache();
return indexPatternCache!
.filter((savedObject: SimpleSavedObject<IndexPatternSavedObjectAttrs>) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

now uses SavedObject instead of SimpleSavedObject - type info is available without specifying.

const indexPatternsMap: SourceIndexMap = {};
const savedObjects = (await mlContext.indexPatterns.getCache()) || [];
savedObjects.forEach((obj: SimpleSavedObject<Record<string, any>>) => {
savedObjects.forEach((obj) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

now uses SavedObject instead of SimpleSavedObject - type info is available without specifying.

Copy link
Contributor

@nreese nreese left a comment

Choose a reason for hiding this comment

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

maps changes LGTM
code review, tested in chrome

Copy link
Contributor

@darnautov darnautov left a comment

Choose a reason for hiding this comment

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

ML changes LGTM

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Build metrics

@kbn/optimizer bundle module count

id value diff baseline
data 208 -1 209

History

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

Copy link
Member

@lukeelmers lukeelmers left a comment

Choose a reason for hiding this comment

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

Overall code LGTM! I just have one question about caching the uiSettings on the client that we should probably sort out, as I'm not sure how big of an issue it might be.

Plugin functional tests were a nice touch, thanks for adding those! 🆒

*/

import { ToastInputFields, ErrorToastOptions } from 'src/core/public/notifications';
// eslint-disable-next-line
Copy link
Member

Choose a reason for hiding this comment

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

Is this disabled because you are importing from server into common and eslint doesn't realize this is a type which will be compiled away?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correct!

async specToIndexPattern(spec: IndexPatternSpec) {
const shortDotsEnable = await this.config.get(UI_SETTINGS.SHORT_DOTS_ENABLE);
const metaFields = await this.config.get(UI_SETTINGS.META_FIELDS);
const uiSettingsValues = await this.config.getAll();
Copy link
Member

Choose a reason for hiding this comment

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

i would prefer not doing getAll at all and rather identify the specific settings that are required if possible ?

We should look at refactoring FieldFormatters so they're not dependent on being passed a dependency like this.

++ To both of these ideas. Ideally we would only include the subset of uiSettings which are actually needed.

One thing I'm still not sure about is whether we are going to run into issues caching the uiSettingsValues like this. What happens if someone updates a uiSetting (on the client) after we have already cached the settings with getAll? Now they will be getting an outdated value. Whereas in the previous implementation (with getConfig) we were calling uiSettings.get each time, which guaranteed you would always be getting the latest value.

Looking at index_pattern.ts it seems getConfig is only called once in the constructor which means this wouldn't be an issue anywhere except in deserializeFieldFormatMap where the cached values are passed to a new FieldFormat instance -- so does this mean that the field formats will all now have a cached version of the ui settings which could potentially be stale?

I'm wondering if instead this cache should be handled internally in the ui settings client/public wrapper, and then subscribe to the uiSettings.getSaved$ observable which (I believe) will broadcast an update any time a setting is updated. This could then be used to update the cached retrieved with getAll:

class UiSettingsPublicToCommon {
  constructor() {
    this.cache = core.uiSettings.getAll();
    this.subscription = core.uiSettings.getSaved$.subscribe(({ key, newValue, oldValue }) => {
      this.cache[key] = newValue;
    });
  }
  get() {
    return Promise.resolve(this.cache[val]);
  }
  stop() {
    // cleanup which would need to be called in the plugin's `stop` 
    this.subscription.unsubscribe();
  }
}

@mattkime
Copy link
Contributor Author

@lukeelmers

Now they will be getting an outdated value. Whereas in the previous implementation (with getConfig) we were calling uiSettings.get each time, which guaranteed you would always be getting the latest value.

This is determined by the lifecycle of uiSettings and the indexPattern class. Calling getConfig in the browser doesn't necessarily get the latest value, it gets the value currently in the browser. Also, I'm not sure its possible to change the value in the browser without reloading the index pattern which would flush the cached uiSettings copy.

so does this mean that the field formats will all now have a cached version of the ui settings which could potentially be stale?

I think it would be good to come up with a case where that could happen. I can't think of one but you might.

Might be worth talking to platform about the lifecycle of uiSettings.

Copy link
Member

@lukeelmers lukeelmers left a comment

Choose a reason for hiding this comment

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

I think it would be good to come up with a case where that could happen. I can't think of one but you might.

I'm going to look into this further, but I don't see a reason why it needs to block merging this PR, especially because it may be a non-issue when #69379 is done anyway.

If I find a concrete test case for a regression, I can create a separate issue to track it, or possibly resolve the issue in the course of the aggs migration work I'm doing, which will also need a shared uiSettings implementation.

@mattkime
Copy link
Contributor Author

fwiw the platform team confirmed my understanding of uiSettings value changes.

@mattkime mattkime merged commit 2fe0051 into elastic:master Jun 30, 2020
@lukeelmers
Copy link
Member

lukeelmers commented Jun 30, 2020

I'm not sure its possible to change the value in the browser without reloading the index pattern which would flush the cached uiSettings copy.

I've looked into this further, and so far I haven't found a case where index patterns aren't reloaded upon navigating away from advanced settings. So even if the cache is technically stale, it won't matter since it gets flushed before users see anything, so folks are not likely to ever see this inconsistency.

mattkime added a commit to mattkime/kibana that referenced this pull request Jun 30, 2020
* index patterns on the server
# Conflicts:
#	docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern._constructor_.md
#	docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md
#	src/plugins/data/common/index_patterns/index_patterns/index_pattern.test.ts
#	src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts
#	src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts
#	src/plugins/data/common/index_patterns/types.ts
#	src/plugins/data/public/index_patterns/index_patterns/index.ts
#	src/plugins/data/public/plugin.ts
#	src/plugins/data/public/public.api.md
mattkime added a commit that referenced this pull request Jul 1, 2020
* index patterns on the server
Bamieh pushed a commit to Bamieh/kibana that referenced this pull request Jul 1, 2020
* index patterns on the server
@mattkime mattkime mentioned this pull request Jul 13, 2020
12 tasks
@mattkime mattkime mentioned this pull request Sep 24, 2020
63 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:Data Views Data Views code and UI - index patterns before 8.0 release_note:skip Skip the PR/issue when compiling release notes v7.9.0 v8.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants