Skip to content

Commit

Permalink
[Discover] Add container for internal state (#144149)
Browse files Browse the repository at this point in the history
Co-authored-by: Dzmitry Tamashevich <[email protected]>
Co-authored-by: Julia Rechkunova <[email protected]>
  • Loading branch information
3 people authored Dec 30, 2022
1 parent 28cf540 commit f87ee1d
Show file tree
Hide file tree
Showing 67 changed files with 1,139 additions and 809 deletions.
1 change: 1 addition & 0 deletions src/plugins/discover/public/__mocks__/data_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const buildDataViewMock = ({
name,
metaFields: ['_index', '_score'],
fields: dataViewFields,
type: 'default',
getName: () => name,
getComputedFields: () => ({ docvalueFields: [], scriptFields: {}, storedFields: ['*'] }),
getSourceFiltering: () => ({}),
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/discover/public/__mocks__/discover_state.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
* Side Public License, v 1.
*/
import { createBrowserHistory } from 'history';
import { getState } from '../application/main/services/discover_state';
import { getDiscoverStateContainer } from '../application/main/services/discover_state';
import { savedSearchMockWithTimeField, savedSearchMock } from './saved_search';
import { discoverServiceMock } from './services';

export function getDiscoverStateMock({ isTimeBased = true }) {
const history = createBrowserHistory();
history.push('/');
return getState({
return getDiscoverStateContainer({
savedSearch: isTimeBased ? savedSearchMockWithTimeField : savedSearchMock,
services: discoverServiceMock,
history,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) =>
config: uiSettings,
dataView,
dataViews,
state: appState,
useNewFieldsApi,
setAppState: stateContainer.setAppState,
columns: appState.columns,
sort: appState.sort,
});

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { EuiFlexItem } from '@elastic/eui';
import { css } from '@emotion/react';
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
import { FIELD_STATISTICS_LOADED } from './constants';
import type { GetStateReturn } from '../../services/discover_state';
import type { DiscoverStateContainer } from '../../services/discover_state';
import { AvailableFields$, DataRefetch$, DataTotalHits$ } from '../../hooks/use_saved_search';
export interface RandomSamplingOption {
mode: 'random_sampling';
Expand Down Expand Up @@ -95,7 +95,7 @@ export interface FieldStatisticsTableProps {
/**
* State container with persisted settings
*/
stateContainer?: GetStateReturn;
stateContainer?: DiscoverStateContainer;
/**
* Callback to add a filter to filter bar
*/
Expand Down Expand Up @@ -136,8 +136,7 @@ export const FieldStatisticsTable = (props: FieldStatisticsTableProps) => {
const embeddableRoot: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);

const showPreviewByDefault = useMemo(
() =>
stateContainer ? !stateContainer.appStateContainer.getState().hideAggregatedPreview : true,
() => (stateContainer ? !stateContainer.appState.getState().hideAggregatedPreview : true),
[stateContainer]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
import { AppState } from '../../../services/discover_app_state_container';
import { getDataViewMock } from '../../../../../__mocks__/__storybook_mocks__/get_data_view_mock';
import { withDiscoverServices } from '../../../../../__mocks__/__storybook_mocks__/with_discover_services';
import { getDocumentsLayoutProps, getPlainRecordLayoutProps } from './get_layout_props';
import { DiscoverLayout } from '../discover_layout';
import { setHeaderActionMenuMounter } from '../../../../../kibana_services';
import { AppState } from '../../../services/discover_state';
import { DiscoverLayoutProps } from '../types';

setHeaderActionMenuMounter(() => void 0);

const DiscoverLayoutStory = (layoutProps: DiscoverLayoutProps) => {
const [state, setState] = useState(layoutProps.state);
const [state, setState] = useState({});

const setAppState = (newState: Partial<AppState>) => {
setState((prevState) => ({ ...prevState, ...newState }));
Expand All @@ -31,10 +31,9 @@ const DiscoverLayoutStory = (layoutProps: DiscoverLayoutProps) => {
return (
<DiscoverLayout
{...layoutProps}
state={state}
stateContainer={{
...layoutProps.stateContainer,
appStateContainer: { ...layoutProps.stateContainer.appStateContainer, getState },
appState: { ...layoutProps.stateContainer.appState, getState },
setAppState,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { buildDataTableRecordList } from '../../../../../utils/build_data_record
import { esHits } from '../../../../../__mocks__/es_hits';
import { SavedSearch } from '../../../../..';
import { DiscoverLayoutProps } from '../types';
import { GetStateReturn } from '../../../services/discover_state';
import { DiscoverStateContainer } from '../../../services/discover_state';

const documentObservables = {
main$: new BehaviorSubject({
Expand Down Expand Up @@ -91,16 +91,15 @@ const getCommonProps = (dataView: DataView) => {
savedSearch: savedSearchMock,
savedSearchRefetch$: new Subject(),
searchSource: searchSourceMock,

stateContainer: {
setAppState: action('Set app state'),
appStateContainer: {
appState: {
getState: () => ({
interval: 'auto',
}),
setState: action('Set app state'),
},
} as unknown as GetStateReturn,
} as unknown as DiscoverStateContainer,
setExpandedDoc: action('opening an expanded doc'),
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { mountWithIntl } from '@kbn/test-jest-helpers';
import { setHeaderActionMenuMounter } from '../../../../kibana_services';
import { esHits } from '../../../../__mocks__/es_hits';
import { savedSearchMock } from '../../../../__mocks__/saved_search';
import { AppState, GetStateReturn } from '../../services/discover_state';
import { DiscoverStateContainer } from '../../services/discover_state';
import { DataDocuments$ } from '../../hooks/use_saved_search';
import { discoverServiceMock } from '../../../../__mocks__/services';
import { FetchStatus } from '../../../types';
Expand All @@ -21,6 +21,9 @@ import { dataViewMock } from '../../../../__mocks__/data_view';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { buildDataTableRecord } from '../../../../utils/build_data_record';
import { EsHitRecord } from '../../../../types';
import { DiscoverMainProvider } from '../../services/discover_state_provider';
import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock';
import { AppState } from '../../services/discover_app_state_container';

setHeaderActionMenuMounter(jest.fn());

Expand All @@ -34,6 +37,8 @@ function mountComponent(fetchStatus: FetchStatus, hits: EsHitRecord[]) {
fetchStatus,
result: hits.map((hit) => buildDataTableRecord(hit, dataViewMock)),
}) as DataDocuments$;
const stateContainer = getDiscoverStateMock({});
stateContainer.setAppState({ index: dataViewMock.id });

const props = {
expandedDoc: undefined,
Expand All @@ -44,14 +49,16 @@ function mountComponent(fetchStatus: FetchStatus, hits: EsHitRecord[]) {
searchSource: documents$,
setExpandedDoc: jest.fn(),
state: { columns: [] },
stateContainer: { setAppState: () => {} } as unknown as GetStateReturn,
stateContainer,
navigateTo: jest.fn(),
onFieldEdited: jest.fn(),
};

return mountWithIntl(
<KibanaContextProvider services={services}>
<DiscoverDocuments {...props} />
<DiscoverMainProvider value={stateContainer}>
<DiscoverDocuments {...props} />
</DiscoverMainProvider>
</KibanaContextProvider>
);
}
Expand Down Expand Up @@ -83,15 +90,17 @@ describe('Discover documents layout', () => {
setAppState: (newState: Partial<AppState>) => {
state = { ...state, ...newState };
},
} as unknown as GetStateReturn;
appState: {
getState: () => state,
},
} as unknown as DiscoverStateContainer;

onResize(
{
columnId: 'someField',
width: 205.5435345534,
},
stateContainer,
state
stateContainer
);

expect(state.grid?.columns?.someField.width).toEqual(206);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { FormattedMessage } from '@kbn/i18n-react';
import { DataView } from '@kbn/data-views-plugin/public';
import { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public';
import { useAppStateSelector } from '../../services/discover_app_state_container';
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
import { DocViewFilterFn } from '../../../../services/doc_views/doc_views_types';
import { DiscoverGrid } from '../../../../components/discover_grid/discover_grid';
Expand All @@ -29,7 +30,7 @@ import {
} from '../../../../../common';
import { useColumns } from '../../../../hooks/use_data_grid_columns';
import { DataDocuments$, RecordRawType } from '../../hooks/use_saved_search';
import { AppState, GetStateReturn } from '../../services/discover_state';
import { DiscoverStateContainer } from '../../services/discover_state';
import { useDataState } from '../../hooks/use_data_state';
import { DocTableInfinite } from '../../../../components/doc_table/doc_table_infinite';
import { DocumentExplorerCallout } from '../document_explorer_callout';
Expand All @@ -45,9 +46,9 @@ const DataGridMemoized = React.memo(DiscoverGrid);
// export needs for testing
export const onResize = (
colSettings: { columnId: string; width: number },
stateContainer: GetStateReturn,
state: AppState
stateContainer: DiscoverStateContainer
) => {
const state = stateContainer.appState.getState();
const grid = { ...(state.grid || {}) };
const newColumns = { ...(grid.columns || {}) };
newColumns[colSettings.columnId] = {
Expand All @@ -64,7 +65,6 @@ function DiscoverDocumentsComponent({
onAddFilter,
savedSearch,
setExpandedDoc,
state,
stateContainer,
onFieldEdited,
}: {
Expand All @@ -75,49 +75,75 @@ function DiscoverDocumentsComponent({
onAddFilter?: DocViewFilterFn;
savedSearch: SavedSearch;
setExpandedDoc: (doc?: DataTableRecord) => void;
state: AppState;
stateContainer: GetStateReturn;
stateContainer: DiscoverStateContainer;
onFieldEdited?: () => void;
}) {
const { capabilities, dataViews, uiSettings } = useDiscoverServices();
const [query, sort, rowHeight, rowsPerPage, grid, columns, index] = useAppStateSelector(
(state) => {
return [
state.query,
state.sort,
state.rowHeight,
state.rowsPerPage,
state.grid,
state.columns,
state.index,
];
}
);

const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]);
const hideAnnouncements = useMemo(() => uiSettings.get(HIDE_ANNOUNCEMENTS), [uiSettings]);
const isLegacy = useMemo(() => uiSettings.get(DOC_TABLE_LEGACY), [uiSettings]);
const sampleSize = useMemo(() => uiSettings.get(SAMPLE_SIZE_SETTING), [uiSettings]);

const documentState = useDataState(documents$);
const isLoading = documentState.fetchStatus === FetchStatus.LOADING;
const isPlainRecord = useMemo(
() => getRawRecordType(state.query) === RecordRawType.PLAIN,
[state.query]
);
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.
// 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
// 5. this is propagated to Discover's URL and causes an unwanted change of state to an unsorted state
// This solution switches to the loading state in this component when the URL index doesn't match the dataView.id
const isDataViewLoading = index && dataView.id && index !== dataView.id;
const isEmptyDataResult = !documentState.result || documentState.result.length === 0;
const isPlainRecord = useMemo(() => getRawRecordType(query) === RecordRawType.PLAIN, [query]);
const rows = useMemo(() => documentState.result || [], [documentState.result]);

const { columns, onAddColumn, onRemoveColumn, onMoveColumn, onSetColumns } = useColumns({
const {
columns: currentColumns,
onAddColumn,
onRemoveColumn,
onMoveColumn,
onSetColumns,
} = useColumns({
capabilities,
config: uiSettings,
dataView,
dataViews,
setAppState: stateContainer.setAppState,
state,
useNewFieldsApi,
columns,
sort,
});

const onResizeDataGrid = useCallback(
(colSettings) => onResize(colSettings, stateContainer, state),
[stateContainer, state]
(colSettings) => onResize(colSettings, stateContainer),
[stateContainer]
);

const onUpdateRowsPerPage = useCallback(
(rowsPerPage: number) => {
stateContainer.setAppState({ rowsPerPage });
(nextRowsPerPage: number) => {
stateContainer.setAppState({ rowsPerPage: nextRowsPerPage });
},
[stateContainer]
);

const onSort = useCallback(
(sort: string[][]) => {
stateContainer.setAppState({ sort });
(nextSort: string[][]) => {
stateContainer.setAppState({ sort: nextSort });
},
[stateContainer]
);
Expand All @@ -137,10 +163,7 @@ function DiscoverDocumentsComponent({
[isPlainRecord, uiSettings, dataView.timeFieldName]
);

if (
(!documentState.result || documentState.result.length === 0) &&
documentState.fetchStatus === FetchStatus.LOADING
) {
if (isDataViewLoading || (isEmptyDataResult && isDataLoading)) {
return (
<div className="dscDocuments__loading">
<EuiText size="xs" color="subdued">
Expand All @@ -163,11 +186,11 @@ function DiscoverDocumentsComponent({
<>
{!hideAnnouncements && <DocumentExplorerCallout />}
<DocTableInfiniteMemoized
columns={columns}
columns={currentColumns}
dataView={dataView}
rows={rows}
sort={state.sort || []}
isLoading={isLoading}
sort={sort || []}
isLoading={isDataLoading}
searchDescription={savedSearch.description}
sharedItemTitle={savedSearch.title}
onAddColumn={onAddColumn}
Expand All @@ -190,30 +213,30 @@ function DiscoverDocumentsComponent({
<div className="dscDiscoverGrid">
<DataGridMemoized
ariaLabelledBy="documentsAriaLabel"
columns={columns}
columns={currentColumns}
expandedDoc={expandedDoc}
dataView={dataView}
isLoading={isLoading}
isLoading={isDataLoading}
rows={rows}
sort={(state.sort as SortOrder[]) || []}
sort={(sort as SortOrder[]) || []}
sampleSize={sampleSize}
searchDescription={savedSearch.description}
searchTitle={savedSearch.title}
setExpandedDoc={!isPlainRecord ? setExpandedDoc : undefined}
showTimeCol={showTimeCol}
settings={state.grid}
settings={grid}
onAddColumn={onAddColumn}
onFilter={onAddFilter as DocViewFilterFn}
onRemoveColumn={onRemoveColumn}
onSetColumns={onSetColumns}
onSort={!isPlainRecord ? onSort : undefined}
onResize={onResizeDataGrid}
useNewFieldsApi={useNewFieldsApi}
rowHeightState={state.rowHeight}
rowHeightState={rowHeight}
onUpdateRowHeight={onUpdateRowHeight}
isSortEnabled={!isPlainRecord}
isPlainRecord={isPlainRecord}
rowsPerPageState={state.rowsPerPage}
rowsPerPageState={rowsPerPage}
onUpdateRowsPerPage={onUpdateRowsPerPage}
onFieldEdited={onFieldEdited}
savedSearchId={savedSearch.id}
Expand Down
Loading

0 comments on commit f87ee1d

Please sign in to comment.