Skip to content

Commit

Permalink
[ML] Data visualizer: Change refresh button in Data View and Data Dri…
Browse files Browse the repository at this point in the history
…ft view to indicate an update is pending (#196537)

## Summary

Updated the refresh button to indicate that an update is pending after a
query change in `Data View` and `Data Drift`.
For: [#176737](#176737)
After:
Data View:



https://github.com/user-attachments/assets/249e4266-957d-4642-9841-603e20213faa



Data drift:


https://github.com/user-attachments/assets/474ad1ec-87e3-4d4b-8f4b-026887f453ea
  • Loading branch information
rbrtj authored Oct 18, 2024
1 parent 720c1cb commit 33f8fdd
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@elastic/eui';

import type { WindowParameters } from '@kbn/aiops-log-rate-analysis';
import type { Filter, Query } from '@kbn/es-query';
import { buildEsQuery, type Filter, type Query } from '@kbn/es-query';
import { useUrlState, usePageUrlState } from '@kbn/ml-url-state';
import type { DataSeriesDatum } from '@elastic/charts/dist/chart_types/xy_chart/utils/series';
import { useStorage } from '@kbn/ml-local-storage';
Expand All @@ -38,6 +38,7 @@ import { css } from '@emotion/react';
import type { SearchQueryLanguage } from '@kbn/ml-query-utils';
import { i18n } from '@kbn/i18n';
import { cloneDeep } from 'lodash';
import { getEsQueryConfig } from '@kbn/data-plugin/common';
import type { SingleBrushWindowParameters } from './document_count_chart_single_brush/single_brush';
import type { InitialSettings } from './use_data_drift_result';
import { useDataDriftStateManagerContext } from './use_state_manager';
Expand All @@ -59,7 +60,11 @@ const dataViewTitleHeader = css({
minWidth: '300px',
});

export const PageHeader: FC = () => {
interface PageHeaderProps {
onRefresh: () => void;
needsUpdate: boolean;
}
export const PageHeader: FC<PageHeaderProps> = ({ onRefresh, needsUpdate }) => {
const [, setGlobalState] = useUrlState('_g');
const { dataView } = useDataSource();

Expand Down Expand Up @@ -121,6 +126,8 @@ export const PageHeader: FC = () => {
showRefresh={!hasValidTimeField}
width="full"
flexGroup={false}
onRefresh={onRefresh}
needsUpdate={needsUpdate}
/>
</EuiFlexGroup>,
]}
Expand All @@ -147,7 +154,7 @@ const isBarBetween = (start: number, end: number, min: number, max: number) => {
};
export const DataDriftPage: FC<Props> = ({ initialSettings }) => {
const {
services: { data: dataService },
services: { data: dataService, uiSettings },
} = useDataVisualizerKibana();
const { dataView, savedSearch } = useDataSource();

Expand All @@ -174,6 +181,10 @@ export const DataDriftPage: FC<Props> = ({ initialSettings }) => {

const [selectedSavedSearch, setSelectedSavedSearch] = useState(savedSearch);

const [localQueryString, setLocalQueryString] = useState<Query['query'] | undefined>(
dataComparisonListState.searchString
);

useEffect(() => {
if (savedSearch) {
setSelectedSavedSearch(savedSearch);
Expand Down Expand Up @@ -352,9 +363,46 @@ export const DataDriftPage: FC<Props> = ({ initialSettings }) => {
? getDataDriftDataLabel(COMPARISON_LABEL, initialSettings?.comparison)
: getDataDriftDataLabel(COMPARISON_LABEL);

const onQueryChange = useCallback((query: Query['query'] | undefined) => {
setLocalQueryString(query);
}, []);

const queryNeedsUpdate = useMemo(
() => localQueryString !== dataComparisonListState.searchString,
[dataComparisonListState.searchString, localQueryString]
);

const handleRefresh = useCallback(() => {
if (queryNeedsUpdate) {
const newQuery = buildEsQuery(
dataView,
{
query: localQueryString || '',
language: searchQueryLanguage,
},
dataService?.query.filterManager.getFilters() ?? [],
uiSettings ? getEsQueryConfig(uiSettings) : undefined
);
setDataComparisonListState({
...dataComparisonListState,
searchString: localQueryString,
searchQuery: newQuery,
});
}
}, [
queryNeedsUpdate,
dataView,
localQueryString,
searchQueryLanguage,
dataService?.query.filterManager,
uiSettings,
setDataComparisonListState,
dataComparisonListState,
]);

return (
<EuiPageBody data-test-subj="dataComparisonDataDriftPage" paddingSize="none" panelled={false}>
<PageHeader />
<PageHeader onRefresh={handleRefresh} needsUpdate={queryNeedsUpdate} />
<EuiSpacer size="m" />
<EuiPageSection paddingSize="none">
<EuiFlexGroup gutterSize="m" direction="column">
Expand All @@ -365,6 +413,7 @@ export const DataDriftPage: FC<Props> = ({ initialSettings }) => {
searchQuery={searchQuery}
searchQueryLanguage={searchQueryLanguage}
setSearchParams={setSearchParams}
onQueryChange={onQueryChange}
/>
</EuiFlexItem>
<EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
dataVisualizerProps.currentSavedSearch
);

const [localQueryString, setLocalQueryString] = useState<Query['query'] | undefined>(
dataVisualizerListState.searchString
);

const { currentDataView, currentSessionId, getAdditionalLinks } = dataVisualizerProps;

const dataViewFields: DataViewField[] = currentDataView.fields;
Expand Down Expand Up @@ -464,6 +468,43 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
},
});

const queryNeedsUpdate = useMemo(
() => (localQueryString !== dataVisualizerListState.searchString ? true : undefined),
[dataVisualizerListState.searchString, localQueryString]
);

const onQueryChange = useCallback((query: Query['query'] | undefined) => {
setLocalQueryString(query);
}, []);

const handleRefresh = useCallback(() => {
if (queryNeedsUpdate) {
const newQuery = buildEsQuery(
currentDataView,
{
query: localQueryString || '',
language: searchQueryLanguage,
},
data.query.filterManager.getFilters() ?? [],
uiSettings ? getEsQueryConfig(uiSettings) : undefined
);
setDataVisualizerListState({
...dataVisualizerListState,
searchString: localQueryString,
searchQuery: newQuery,
});
}
}, [
queryNeedsUpdate,
currentDataView,
localQueryString,
searchQueryLanguage,
data.query.filterManager,
uiSettings,
setDataVisualizerListState,
dataVisualizerListState,
]);

return (
<EuiPageTemplate
offset={0}
Expand Down Expand Up @@ -514,6 +555,8 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
isAutoRefreshOnly={!hasValidTimeField}
showRefresh={!hasValidTimeField}
width="full"
needsUpdate={queryNeedsUpdate}
onRefresh={handleRefresh}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand All @@ -537,6 +580,7 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
setVisibleFieldNames={setVisibleFieldNames}
showEmptyFields={showEmptyFields}
onAddFilter={onAddFilter}
onQueryChange={onQueryChange}
/>

{overallStats?.totalCount !== undefined && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import type { Filter, Query, TimeRange } from '@kbn/es-query';
import { buildEsQuery } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { isDefined } from '@kbn/ml-is-defined';
import type { DataView } from '@kbn/data-views-plugin/common';
import type { SearchQueryLanguage } from '@kbn/ml-query-utils';
import { getEsQueryConfig } from '@kbn/data-plugin/common';
import { debounce } from 'lodash';
import { useDataVisualizerKibana } from '../../../kibana_context';

export const SearchPanelContent = ({
Expand All @@ -21,11 +22,13 @@ export const SearchPanelContent = ({
searchQueryLanguage,
dataView,
setSearchParams,
onQueryChange,
}: {
dataView: DataView;
searchQuery: Query['query'];
searchString: Query['query'];
searchQueryLanguage: SearchQueryLanguage;
onQueryChange?: (query: Query['query'] | undefined) => void;
setSearchParams({
searchQuery,
searchString,
Expand Down Expand Up @@ -77,6 +80,8 @@ export const SearchPanelContent = ({
uiSettings ? getEsQueryConfig(uiSettings) : undefined
);

// Additional call because the search bar doesn't call onQueryChange when the query is cleared from filters
onQueryChange?.(mergedQuery.query);
setSearchParams({
searchQuery: combinedQuery,
searchString: mergedQuery.query,
Expand All @@ -93,6 +98,18 @@ export const SearchPanelContent = ({
}
};

// Debounce the onQueryChange to prevent race condition when filters are updated and both `onQuerySubmit` and `onQueryChange` are called.
const debouncedOnQueryChange = useCallback(
(inputQuery: Query['query'] | undefined) => {
const debouncedFunction = debounce((debouncedQuery: Query['query'] | undefined) => {
onQueryChange?.(debouncedQuery);
}, 100);

return debouncedFunction(inputQuery);
},
[onQueryChange]
);

return (
<SearchBar
dataTestSubj="dataVisualizerQueryInput"
Expand All @@ -112,6 +129,9 @@ export const SearchPanelContent = ({
displayStyle={'inPage'}
isClearable={true}
customSubmitButton={<div />}
onQueryChange={({ query }) => {
debouncedOnQueryChange?.(query?.query);
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface Props {
}): void;
showEmptyFields: boolean;
onAddFilter?: (field: DataViewField | string, value: string, type: '+' | '-') => void;
onQueryChange?: (query: Query['query'] | undefined) => void;
}

export const SearchPanel: FC<Props> = ({
Expand All @@ -62,6 +63,7 @@ export const SearchPanel: FC<Props> = ({
visibleFieldNames,
setSearchParams,
showEmptyFields,
onQueryChange,
}) => {
const dvSearchPanelControls = css({
marginLeft: '0px !important',
Expand Down Expand Up @@ -101,6 +103,7 @@ export const SearchPanel: FC<Props> = ({
searchString={searchString}
searchQuery={searchQuery}
searchQueryLanguage={searchQueryLanguage}
onQueryChange={onQueryChange}
/>
</EuiFlexItem>

Expand Down

0 comments on commit 33f8fdd

Please sign in to comment.