-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Discover] Add container for internal state #144149
Conversation
…-ref HEAD~1..HEAD --fix'
…to discover-internal-state
[Discover] Make adhoc data view logic more explicit
export function getInternalStateContainer() { | ||
return createStateContainer<InternalState, InternalStateTransitions, {}>( | ||
{ | ||
dataView: undefined, | ||
dataViewAdHocList: [], | ||
}, | ||
{ | ||
setDataView: (prevState: InternalState) => (nextDataView: DataView) => ({ | ||
...prevState, | ||
dataView: nextDataView, | ||
}), | ||
appendAdHocDataView: (prevState: InternalState) => (dataViewAdHoc: DataView) => ({ | ||
...prevState, | ||
dataViewAdHocList: prevState.dataViewAdHocList.concat(dataViewAdHoc), | ||
}), | ||
removeAdHocDataViewById: (prevState: InternalState) => (id: string) => ({ | ||
...prevState, | ||
dataViewAdHocList: prevState.dataViewAdHocList.filter((dataView) => dataView.id !== id), | ||
}), | ||
replaceAdHocDataViewWithId: | ||
(prevState: InternalState) => (prevId: string, newDataView: DataView) => ({ | ||
...prevState, | ||
dataViewAdHocList: prevState.dataViewAdHocList.map((dataView) => | ||
dataView.id === prevId ? newDataView : dataView | ||
), | ||
}), | ||
}, | ||
{}, | ||
{ freeze: (state) => state } | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is where the internal state container is created
InternalStateTransitions | ||
>; | ||
|
||
export const { Provider: InternalStateProvider, useSelector: useInternalStateSelector } = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where Provider
/ useSelector
hook are initialized
@@ -101,10 +98,8 @@ export function DiscoverMainApp(props: DiscoverMainProps) { | |||
useSavedSearchAliasMatchRedirect({ savedSearch, spaces, history }); | |||
|
|||
return ( | |||
<DiscoverAppStateProvider value={stateContainer.appStateContainer}> | |||
<DiscoverMainProvider value={stateContainer}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's where AppState
& InternalState
providers get the stateContainer assigned
<DiscoverStateProvider value={value}> | ||
<DiscoverAppStateProvider value={value.appState}> | ||
<InternalStateProvider value={value.internalState}>{children}</InternalStateProvider> | ||
</DiscoverAppStateProvider> | ||
</DiscoverStateProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combining multiple providers to a single one, more convenient when writing tests
Pinging @elastic/kibana-data-discovery (Team:DataDiscovery) |
@elasticmachine merge upstream |
dear @mattkime if you have the resources, could you review this PR? But be careful! Everbody had to go on well deserved vacation during the reviews 😄 .... this is a so called |
@elasticmachine merge upstream |
expect(updatedDataView!.id).toEqual('updated-mock-id'); | ||
}); | ||
|
||
it('should update the adHocList correctly for text based mode', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is list is no longer stored in this hook, moved to internal state, that's why I removed this test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unified search changes LGTM! I did some tests on text based mode and works as expected 👏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally adhoc data views related functionality one more time and it works as expected!
() => getRawRecordType(state.query) === RecordRawType.PLAIN, | ||
[state.query] | ||
); | ||
// this is needed to prevent data view pushing onSort because there has been a state change with a new data view |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to walk through the code so you can show me this. It sounds like a good test of whether I understand this code. Also, it sounds like a flaw in the state model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've improved documentation why this is written that way .. generally it's fixing a situation when switching between data views with different timestamps, by showing the loading state for this cases. Not saying this is ideal. I've improved the documentation for this, and happy to have a chat about it for sure 👍
src/plugins/discover/public/application/main/discover_main_route.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a couple of comments. While this PR is very big, it seems like a large number of small changes. Lets just touch base before I give the official 👍 since I'm still new to this code.
// 1. When switching the data view, the sorting in the URL is reset to the default sorting of the selected data view. | ||
// 2. The new sort param is already available in this component and propagated to the EuiDataGrid. | ||
// 3. currentColumns are still referring to the old state | ||
// 4. since the new sort by field isn't available in currentColumns EuiDataGrid is emitting a 'onSort', which is unsorting the grid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's where EuiDataGrid calls the onSort event:
); | ||
const isDataLoading = documentState.fetchStatus === FetchStatus.LOADING; | ||
// This is needed to prevent EuiDataGrid pushing onSort because the data view has been switched. | ||
// 1. When switching the data view, the sorting in the URL is reset to the default sorting of the selected data view. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the logic what's happening with the state when a data view is switched:
kibana/src/plugins/discover/public/application/main/utils/get_switch_data_view_app_state.ts
Lines 38 to 58 in 1a213bd
// when switching from an data view with timeField to an data view without timeField | |
// filter out sorting by timeField in case it is set. data views without timeField don't | |
// prepend this field in the table, so in legacy grid you would need to add this column to | |
// remove sorting | |
let nextSort = getSortArray(currentSort, nextDataView).filter((value) => { | |
return nextDataView.timeFieldName || value[0] !== currentDataView.timeFieldName; | |
}); | |
if (nextDataView.isTimeBased() && !nextSort.length) { | |
// set default sorting if it was not set | |
nextSort = [[nextDataView.timeFieldName, sortDirection]]; | |
} else if ( | |
nextDataView.isTimeBased() && | |
currentDataView.isTimeBased() && | |
nextDataView.timeFieldName !== currentDataView.timeFieldName | |
) { | |
// switch time fields | |
nextSort = nextSort.map((cur) => | |
cur[0] === currentDataView.timeFieldName ? [nextDataView.timeFieldName, cur[1]] : cur | |
); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changes look good to me and work well, nice work!
💚 Build Succeeded
Metrics [docs]Module Count
Async chunks
Page load bundle
Unknown metric groupsasync chunk count
References to deprecated APIs
History
To update your PR or re-run it, just comment with: cc @kertal |
Summary
This PR introduces a new state container for the internal state, that's the state used in several components but not synced with the URL (While appState and globalState are synced with the URL). For a start, it contains the currently selected
dataView
,savedDataViews
, and the list of currently available ad-hoc data viewsadHocDataViews
.This new state container is part of
DiscoverStateContainer
(formerly known asGetStateReturn
), preparing for the consolidation of various state-related code in a central container drafted in #140765.Additionally this PR adds more usage of selector hooks, allowing a more granular way to update parts of the UI when there are changes of state, and cleans up ad-hoc data related code.
This PR allows us to move forward to enable editing of data views directly in Discover like Lens #142723
Resolves #145074
Testing
This is a refactoring, everything should work like before
Checklist