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

[Discover] Add container for internal state #144149

Merged
merged 52 commits into from
Dec 30, 2022

Conversation

kertal
Copy link
Member

@kertal kertal commented Oct 27, 2022

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 views adHocDataViews.

export interface InternalState {
  dataView: DataView | undefined;
  savedDataViews: DataViewListItem[];
  adHocDataViews: DataView[];
}

This new state container is part of DiscoverStateContainer (formerly known as GetStateReturn), 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

@kertal kertal self-assigned this Oct 28, 2022
@kertal kertal added Feature:Discover Discover Application Team:DataDiscovery Discover, search (e.g. data plugin and KQL), data views, saved searches. For ES|QL, use Team:ES|QL. release_note:skip Skip the PR/issue when compiling release notes v8.6.0 labels Oct 28, 2022
@kertal kertal changed the title [Discover] Add internal state [Discover] Add container for internal state Oct 28, 2022
Comment on lines 38 to 68
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 }
);
}
Copy link
Member Author

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 } =
Copy link
Member Author

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}>
Copy link
Member Author

@kertal kertal Nov 4, 2022

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

Comment on lines +31 to +35
<DiscoverStateProvider value={value}>
<DiscoverAppStateProvider value={value.appState}>
<InternalStateProvider value={value.internalState}>{children}</InternalStateProvider>
</DiscoverAppStateProvider>
</DiscoverStateProvider>
Copy link
Member Author

@kertal kertal Nov 4, 2022

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

@kertal kertal marked this pull request as ready for review November 4, 2022 09:59
@kertal kertal requested a review from a team as a code owner November 4, 2022 09:59
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-data-discovery (Team:DataDiscovery)

@kertal
Copy link
Member Author

kertal commented Nov 7, 2022

@elasticmachine merge upstream

@kertal
Copy link
Member Author

kertal commented Dec 20, 2022

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 vacationizer PR 🌴

@kertal
Copy link
Member Author

kertal commented Dec 21, 2022

@elasticmachine merge upstream

expect(updatedDataView!.id).toEqual('updated-mock-id');
});

it('should update the adHocList correctly for text based mode', async () => {
Copy link
Member Author

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

@stratoula stratoula removed the ci:cloud-deploy Create or update a Cloud deployment label Dec 22, 2022
Copy link
Contributor

@stratoula stratoula left a 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 👏

@kertal kertal added the chore label Dec 22, 2022
Copy link
Contributor

@dimaanj dimaanj left a 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
Copy link
Contributor

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.

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'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 👍

Copy link
Contributor

@mattkime mattkime 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 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
Copy link
Member Author

Choose a reason for hiding this comment

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

);
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.
Copy link
Member Author

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:

// 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
);
}

@kertal kertal requested a review from mattkime December 29, 2022 13:44
Copy link
Contributor

@mattkime mattkime left a 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!

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
discover 442 448 +6

Async chunks

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

id before after diff
discover 414.2KB 407.3KB -7.0KB
unifiedSearch 273.3KB 273.3KB +1.0B
total -6.9KB

Page load bundle

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

id before after diff
discover 28.0KB 28.0KB +29.0B
Unknown metric groups

async chunk count

id before after diff
discover 9 10 +1

References to deprecated APIs

id before after diff
discover 35 30 -5

History

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

cc @kertal

@kertal kertal merged commit f87ee1d into elastic:main Dec 30, 2022
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Dec 30, 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 chore Feature:Discover Discover Application release_note:skip Skip the PR/issue when compiling release notes Team:DataDiscovery Discover, search (e.g. data plugin and KQL), data views, saved searches. For ES|QL, use Team:ES|QL. v8.7.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Discover] Add internal state container
9 participants