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

[Logs UI] Use the Unified Search Bar for date range selection #144351

Merged

Conversation

weltenwort
Copy link
Member

@weltenwort weltenwort commented Nov 1, 2022

πŸ“ Summary

This enables the date-picker of the unified search bar introduced into the Logs UI in #143222 and simultaneously removes the custom date picker.

closes #142767

🎨 Previews

image

πŸ•΅οΈβ€β™€οΈ Implementation notes

kibana_utils changes

The kibana_utils plugin now also exports IStateStorage so additional storages can be implemented.

Alerts page test changes

The functional test of the observability alerts page were coupled to the assumed default state of the log stream. I changed them to use the observability overview for external timefilter checks instead and cleaned up some of the navigation code.

logPosition state

The log position state is now expressed using a state container, which is synced with the url and unified search bar via the common syncState utility in combination with a KbnUrlStateStorage and a newly implemented TimefilterStateStorage respectively.

%%{init: { "sequence": { "mirrorActors": false } } }%%
sequenceDiagram

participant LogPositionProvider
participant useLogPosition
participant logPositionStateContainer
participant useLogPositionUrlStateSync
participant useLogPositionTimefilterStateSync

LogPositionProvider -->>+ useLogPosition: mount

useLogPosition -->> useLogPositionUrlStateSync: read initial value
useLogPosition -->> useLogPositionTimefilterStateSync: read initial value

useLogPosition -->>+ logPositionStateContainer: create with merged initial values

useLogPosition -->>+ useLogPositionUrlStateSync: effect: start sync
useLogPosition -->>+ useLogPositionTimefilterStateSync: effect: start sync

useLogPositionUrlStateSync -->>- useLogPosition: effect end: stop sync
useLogPositionTimefilterStateSync -->>- useLogPosition: effect end: stop sync

useLogPosition -->>- LogPositionProvider: unmount

deactivate logPositionStateContainer
Loading

The structure of the logPosition URL query parameter remains compatible, but is now validated via io-ts and ignored if invalid.

For simplicity, the actual representation of the timeRange and refreshInterval states are closer to the structure used in the timefilter service. The streaming state is derived on-the-fly from the refresh pause toggle and value.

TimefilterStateStorage

In order to be able to use the common syncState utility, I added a state storage that is backed by the timefilter service. That means in contrast to other state storages it doesn't support arbitrary key-value pairs. I tried to represent that in its interface types.

Date-picker and "stream live" buttom

I left the "stream live" buttom on the second row and reduced it to an EuiEmptyButton to prevent clashes with the refresh button of the search bar.

The streaming mode can be enabled/disabled both via that button or via the refresh settings of the datepicker.

@weltenwort weltenwort added Feature:Logs UI Logs UI feature Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services labels Nov 1, 2022
@weltenwort weltenwort self-assigned this Nov 1, 2022
@weltenwort weltenwort force-pushed the logs-unified-search-bar-datepicker branch from 25eff4e to e35620f Compare November 2, 2022 10:20
@Kerry350 Kerry350 self-requested a review November 2, 2022 15:31
Copy link
Contributor

@Kerry350 Kerry350 left a comment

Choose a reason for hiding this comment

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

Thanks for the detailed description β™₯️

Dropping a comment on from my functional review before I look at the code. On the whole this seemed to work really well, and I know the state wasn't simple to untangle so big kudos for how solid everything felt.

I did run in to some issues with "Stream live" and refresh intervals. When I turn on streaming this is persisted to the URL (the streamLive boolean), but the refresh interval isn't.

This results in some surprising behaviour on refresh of the page:

On refresh this is set to 0 and I see a small warning icon:

Screenshot 2022-11-02 at 15 15 29

Screenshot 2022-11-02 at 15 15 36

Due to the overall streamLive boolean state being persisted to the URL the button does return to being "on", and the streaming message does display at the bottom of the stream, but no requests are actually dispatched on an interval.

Screenshot 2022-11-02 at 15 21 57

Quickly looking at the code this makes sense as refreshInterval ends up getting set to:

{
  pause: false,
  value: 0
} 

in this scenario (due to updateStateFromTimefilterState(), where a 0 bug exists: https://github.com/elastic/kibana/pull/144389/files#r1011529270), and the useInterval returns null when latestLogPositionState.refreshInterval.value <= 0.

Apart from this my other tests seemed to work as expected. I'll take a look at the code now.

@weltenwort
Copy link
Member Author

I did run in to some issues with "Stream live" and refresh intervals. When I turn on streaming this is persisted to the URL (the streamLive boolean), but the refresh interval isn't.

That's true. We never had the interval in the URL and I didn't want to change the URL param structure for now due to BWC. I'll look into working around that by setting it to 5s if it's 0s.

Copy link
Contributor

@Kerry350 Kerry350 left a comment

Choose a reason for hiding this comment

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

I left a few minor comments / questions regarding the code but all in all it looks really solid to me. Thanks for investing the time with the state containers, state storage etc. Even though some of this might change with the state refactoring I think it sets up a really good foundation overall β€” it was definitely a lot easier to follow than what we had previously. I might just have to brush up on some functional programming concepts πŸ˜„

@weltenwort
Copy link
Member Author

@Kerry350 thanks for the feedback

I hope to have fixed the tests by reducing the strictness of the url state parsing a bit by making all properties optional (as they were before).

I also tried to address the refresh interval problem you discovered. To do that I had to move the visiblePosition state into the state container too, so it can be kept in sync with the targetPosition. I think it works out pretty well with latestPosition taking over the role of the separate visibleMidpoint state we had before. Let me know what you think.

Additionally, I removed the dependency on redux-logger in favor of connecting the redux devtools browser extension. It's read-only for now, but that's all I needed for debugging. This should help to keep the bundle smaller.

@weltenwort weltenwort marked this pull request as ready for review November 4, 2022 19:00
@weltenwort weltenwort requested review from a team as code owners November 4, 2022 19:00
@elasticmachine
Copy link
Contributor

Pinging @elastic/infra-monitoring-ui (Team:Infra Monitoring UI)

@Kerry350
Copy link
Contributor

Kerry350 commented Nov 8, 2022

@weltenwort

The functionality seems to work as expected now with regards to refresh intervals πŸ™

Unfortunately, my testing was a bit inconsistent with regards to the stream live button. When I try to turn streaming on or off (via the button) I seem to hit something that causes the call stack to be exceeded and the browser locks up. I've tried this with and without Redux dev tools, and with the dev tools closed entirely, and it still seems to happen. I don't see anything obvious (like Redux dev tools being spammed with actions or something similar). But there is a message about payloads being too large (sometimes), but I don't see an abnormally sized payload in the dev tools.

This doesn't happen via the "Refresh every" toggle in the date picker, it's just the button. I'd say it happens 90% of the time.

(I guess it's not 100% clear in the gif, but the mouse cursor kind of denotes when it's locked up).

stream

Screenshot 2022-11-08 at 13 03 42

In terms of data I'm using an oblt-cli generated cluster against Edge.

@weltenwort
Copy link
Member Author

Good catch! I was able to reproduce that and find the cause:

The startLiveStreaming and stopLiveStreaming transitions are used directly as React event handlers. That means they were called with the respective SyntheticEvent as the argument, which doesn't play well with the devtool's attempt to serialize it.

I added a safeguard against that. Unfortunately there's no "official" way to check whether a value is a SyntheticEvent. 😬

@kibana-ci
Copy link
Collaborator

πŸ’š Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
infra 1105 1114 +9

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
kibanaUtils 420 424 +4

Async chunks

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

id before after diff
infra 1.1MB 1.1MB +19.0KB
observability 485.7KB 485.7KB +55.0B
total +19.0KB

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
kibanaUtils 9 8 -1

Page load bundle

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

id before after diff
infra 85.4KB 85.6KB +223.0B
Unknown metric groups

API count

id before after diff
kibanaUtils 615 624 +9

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 59 65 +6
infra 45 44 -1
osquery 108 113 +5
securitySolution 440 446 +6
total +18

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 67 73 +6
infra 53 52 -1
osquery 109 115 +6
securitySolution 517 523 +6
total +19

History

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

cc @weltenwort

await setTimeRangeToXDaysAgo(10);
await (await find.byLinkText('Alerts')).click();
await pageObjects.observability.clickSolutionNavigationEntry(
Copy link
Member

Choose a reason for hiding this comment

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

πŸ‘πŸ»

await numerOfDaysField.clearValueWithKeyboard();
await numerOfDaysField.type(numberOfDays.toString());
const numberField = await find.byCssSelector('[aria-label="Time value"]');
await numberField.clearValueWithKeyboard();
Copy link
Member

Choose a reason for hiding this comment

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

Was there an issue that led to this change or is it an improvement?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, previously the test assumed that "days" was selected as the time unit and it therefore just changed the number. But now the previous date picker state might contain "hours", so the test needs to explicitly set it to "days".

Copy link
Member

@maryam-saeidi maryam-saeidi left a comment

Choose a reason for hiding this comment

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

AO changes LGTM!

Copy link
Contributor

@Kerry350 Kerry350 left a comment

Choose a reason for hiding this comment

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

Thanks for the patience whilst I worked through the review πŸ™ I couldn't find any issues. I know this wasn't a trivial issue at all, great work πŸ™Œ

I think it works out pretty well with latestPosition taking over the role of the separate visibleMidpoint state we had before. Let me know what you think.

Agreed, this seemed like a positive change to me, and a better location.

I added a safeguard against that. Unfortunately there's no "official" way to check whether a value is a SyntheticEvent. 😬

Nice one catching the problem here. For all it would be nice to have an "official" method thanks for making it obvious with the helper functions.

I can confirm this was fixed in my testing:

stream

...config,
serialize: {
...(typeof config?.serialize === 'object' ? config.serialize : {}),
replacer: (_key: string, value: unknown) => replaceReactSyntheticEvent(value),
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ‘πŸ‘

@weltenwort weltenwort changed the title [Logs UI] Support the Unified Search Bar for date range selection [Logs UI] Use the Unified Search Bar for date range selection Nov 9, 2022
refreshInterval?: RefreshInterval;
}

export const createTimefilterStateStorage = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting approach! haven't thought of it.

There is an existing util that sets up syncing between a state container and data services. In addition to time range it also supports filters and query, but can be configured to only sync time range

src/plugins/data/public/query/state_sync/connect_to_query_state.ts

The usage would be something like this:

const stop = connectToQueryState(data.query, stateContainer, { time: true, refreshInterval: true})

Take a look! Maybe this could work well and will allow to clean up some code (the new code looks good tbh πŸ‘ )

Otherwise lgtm, no objections exporting more interfaces

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't know about that utility πŸ’‘ thanks for pointing it out

@weltenwort weltenwort merged commit c88a680 into elastic:main Nov 9, 2022
@weltenwort weltenwort deleted the logs-unified-search-bar-datepicker branch November 9, 2022 17:49
@kibanamachine kibanamachine added v8.6.0 backport:skip This commit does not require backporting labels Nov 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Logs UI Logs UI feature release_note:enhancement Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services v8.6.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Logs UI] Use Unified Search Bar: support date picker
8 participants