Skip to content

[data view editor] Form state refactor - create service, replace useEffect with observables#142421

Merged
mattkime merged 39 commits intoelastic:mainfrom
mattkime:refactor_data_view_create
Oct 18, 2022
Merged

[data view editor] Form state refactor - create service, replace useEffect with observables#142421
mattkime merged 39 commits intoelastic:mainfrom
mattkime:refactor_data_view_create

Conversation

@mattkime
Copy link
Copy Markdown
Contributor

@mattkime mattkime commented Oct 1, 2022

Summary

  • Created service which is passed into flyout like a plugin dependency, sidestepping react state concerns
  • Code is rewritten to use observables instead of react state / useEffect
    • There's just one useEffect function
    • All useState has been replaced by useRef wrapped Subject and BehaviorSubject objects
  • Fixes UI updates on 'Show hidden indices' toggle
  • Fixes index name highlighting when index pattern has multiple (comma delineated) segments
  • Fixes data view edit use case
  • All network requests are debounced

Note: I attempted further refactoring but ran into problems. These changes are sufficient to provide a number of bug fixes.

Follow up to and in support of #142362

@mattkime mattkime changed the title replace useEffect with observables as much as possible [data view editor] Form state refactor - replace useEffect with observables Oct 2, 2022
@mattkime mattkime added Feature:Data Views Data Views code and UI - index patterns before 8.0 Feature:Kibana Management Feature label for Data Views, Advanced Setting, Saved Object management pages release_note:skip Skip the PR/issue when compiling release notes labels Oct 8, 2022
@mattkime mattkime requested a review from flash1293 October 8, 2022 14:17
@mattkime mattkime marked this pull request as ready for review October 8, 2022 14:19
@mattkime mattkime requested review from a team as code owners October 8, 2022 14:19
@mattkime mattkime added the v8.6.0 label Oct 8, 2022
@mattkime mattkime changed the title [data view editor] Form state refactor - replace useEffect with observables [data view editor] Form state refactor - create service, replace useEffect with observables Oct 10, 2022
@mattkime
Copy link
Copy Markdown
Contributor Author

@Dosant I've modified the code to eliminate the possibility of stale data between flyout invocations. I saw the timestamp field being populated without an index pattern - this has been fixed.

I've reduced the number of indices requests but I don't think I'll address the fields_for_wildcard as there's some unfortunate code thats tied to validation - that I hope to clean up in a subsequent PR.

@ppisljar
Copy link
Copy Markdown
Contributor

ppisljar commented Oct 11, 2022

I've reduced the number of indices requests but I don't think I'll address the fields_for_wildcard as there's some unfortunate code thats tied to validation - that I hope to clean up in a subsequent PR.

If the consequence of this PR are additional (not needed) requests and thus reduced performance then we can either address the issue in this PR or merge this PR into a feature branch and resolve the issue in the followup and once its resolved we can merge the feature branch into main.


private getIndicesMemory: Record<string, Promise<MatchedItem[]>> = {};
debounceGetIndices = async (props: { pattern: string; showAllIndices?: boolean | undefined }) => {
const debouncedRequest = debounce(this.dataViews.getIndices, 60000, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think I don't understand why we wrap this into debounce. since this function would be called only once - I guess there is no need to debounce it.

Was the intention to make the cache live for 60 seconds? Then I think it doesn't work this way and instead cache is alive for as long as the instance of the service is alive. Because with every getIndicesMemory call we get the cached promise from memory instead of calling the debounced function again

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ah, good catch! No, debounce isn't needed. I've removed it. I think its okay for us to cache the response for the life of the flyout.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah, Sounds good then 👍

Should we clean up the cache in case of an error?

Copy link
Copy Markdown
Contributor Author

@mattkime mattkime Oct 12, 2022

Choose a reason for hiding this comment

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

Should we clean up the cache in case of an error?

Definitely.


this.getIndicesMemory[key] =
this.getIndicesMemory[key] ||
this.dataViews.getIndices({ ...props, isRollupIndex: await this.getIsRollupIndex() });
Copy link
Copy Markdown
Contributor

@Dosant Dosant Oct 12, 2022

Choose a reason for hiding this comment

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

This probably won't be visible for the end user, but because of this await, we'd have a delay between putting the promise into the cache and accessing the cache.

This code could be read like this:

if (!this.getIndicesMemory[key]) {
const isRollup = await this.getIsRollupIndex(); // <---- breaking the sync execution. gives a chance for other code to run "in parallel" 
this.getIndicesMemory[key] = this.dataViews.getIndices({ ...props, isRollupIndex: isRollup });
}

this means that there is a moment when getIndicesMemory can be called again and there is no promise yet in the cahche and then we do a redundant request.

this looks uglier, but probably can be fixed like this:

if (!this.getIndicesMemory[key]) {
this.getIndicesMemory[key] = this.getIsRollupIndex().then(isRollup => this.dataViews.getIndices({ ...props, isRollupIndex: isRollup }))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we can also leave it as is, if we think this isn't a problem at all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Practically speaking I think the code is fine but I like the formally correct solution you've proposed.

@Dosant
Copy link
Copy Markdown
Contributor

Dosant commented Oct 17, 2022

Recent code changes lgtm.

I tried to smoke check and noticed that I can't edit -> save data view anymore. I couldn't reproduce in main:

can.t.save.mov

@mattkime
Copy link
Copy Markdown
Contributor Author

@Dosant Addressed and added test

@kibana-ci
Copy link
Copy Markdown

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
dataViewEditor 60 63 +3

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
dataViewEditor 31.2KB 34.7KB +3.5KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
dataViewEditor 10.4KB 10.5KB +97.0B
Unknown metric groups

ESLint disabled in files

id before after diff
dataViewEditor 3 1 -2

ESLint disabled line counts

id before after diff
dataViewEditor 4 2 -2

Total ESLint disabled count

id before after diff
dataViewEditor 7 3 -4

History

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

Copy link
Copy Markdown
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

Tested, seemed to be working well :)

@mattkime mattkime merged commit 74595de into elastic:main Oct 18, 2022
@kibanamachine kibanamachine added the backport:skip This PR does not require backporting label Oct 18, 2022
kc13greiner pushed a commit to kc13greiner/kibana that referenced this pull request Oct 18, 2022
…ffect with observables (elastic#142421)

* replace useEffect with observables as much as possible

* cleanup, fix timestamp field / allow hidden bug
mattkime added a commit that referenced this pull request Nov 29, 2022
…rvice and out of react state management (#143604)

## Summary

This PR completes the data view editor state service. Of note:
- All form business logic is now in service although validation is still
handled by the form lib
- Service is initialized with dependencies, form config, and initial
state
- Service state is updated via simple method calls
- Service state updates are provided to React code via observables using
`useObservable`
- Service is provided via parent component which uses `useRef` so the
service is created once per flyout creation

IMO the diff isn't very helpful. It might be easier to review the
changed files in completion.

Follow up to #142421

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:Data Views Data Views code and UI - index patterns before 8.0 Feature:Kibana Management Feature label for Data Views, Advanced Setting, Saved Object management pages release_note:skip Skip the PR/issue when compiling release notes v8.6.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants