From a24cb41bab89f28040b53ce0d3ceaee9acba98cc Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Sat, 27 Jun 2020 11:10:27 +0200 Subject: [PATCH] [ML] WIP --- .../application/explorer/anomaly_timeline.tsx | 92 ++++++++----------- .../public/application/explorer/explorer.js | 23 ----- .../explorer/explorer_constants.ts | 2 + .../clear_influencer_filter_settings.ts | 1 + .../explorer_reducer/job_selection_change.ts | 1 + .../reducers/explorer_reducer/reducer.ts | 5 + .../set_influencer_filter_settings.ts | 1 + .../explorer/swimlane_container.tsx | 61 +++++++++--- .../application/routing/routes/explorer.tsx | 17 ++-- 9 files changed, 106 insertions(+), 97 deletions(-) diff --git a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx index 0f9032b50eb73ac..0fd8d9669b3030a 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx @@ -35,7 +35,6 @@ import { import { ExplorerState } from './reducers/explorer_reducer'; import { hasMatchingPoints } from './has_matching_points'; import { ExplorerNoInfluencersFound } from './components/explorer_no_influencers_found/explorer_no_influencers_found'; -import { LoadingIndicator } from '../components/loading_indicator'; import { SwimlaneContainer } from './swimlane_container'; import { OverallSwimlaneData } from './explorer_utils'; @@ -169,11 +168,6 @@ export const AnomalyTimeline: FC = React.memo( } }, []); - const showOverallSwimlane = - overallSwimlaneData !== null && - overallSwimlaneData.laneLabels && - overallSwimlaneData.laneLabels.length > 0; - const showViewBySwimlane = viewBySwimlaneData !== null && viewBySwimlaneData.laneLabels && @@ -295,56 +289,50 @@ export const AnomalyTimeline: FC = React.memo( onMouseLeave={onSwimlaneLeaveHandler} data-test-subj="mlAnomalyExplorerSwimlaneOverall" > - {showOverallSwimlane && ( - explorerService.setSwimlaneContainerWidth(width)} - /> - )} + explorerService.setSwimlaneContainerWidth(width)} + /> {viewBySwimlaneOptions.length > 0 && ( <> - {showViewBySwimlane && ( - <> - -
- explorerService.setSwimlaneContainerWidth(width)} - fromPage={viewByFromPage} - perPage={viewByPerPage} - /> -
- - )} - - {viewBySwimlaneDataLoading && } + <> + +
+ explorerService.setSwimlaneContainerWidth(width)} + fromPage={viewByFromPage} + perPage={viewByPerPage} + /> +
+ {!showViewBySwimlane && !viewBySwimlaneDataLoading && diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index cc4448a50ed0b99..df5811f686472f1 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -34,7 +34,6 @@ import { DatePickerWrapper } from '../components/navigation_menu/date_picker_wra import { InfluencersList } from '../components/influencers_list'; import { explorerService } from './explorer_dashboard_service'; import { AnomalyResultsViewSelector } from '../components/anomaly_results_view_selector'; -import { LoadingIndicator } from '../components/loading_indicator/loading_indicator'; import { NavigationMenu } from '../components/navigation_menu'; import { CheckboxShowCharts } from '../components/controls/checkbox_showcharts'; import { JobSelector } from '../components/job_selector'; @@ -224,28 +223,6 @@ export class Explorer extends React.Component { const noJobsFound = selectedJobs === null || selectedJobs.length === 0; const hasResults = overallSwimlaneData.points && overallSwimlaneData.points.length > 0; - if (loading === true) { - return ( - - - - ); - } - if (noJobsFound) { return ( diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts index 32b51bee64f86dc..be7b2289cf1b956 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts @@ -67,3 +67,5 @@ export const VIEW_BY_JOB_LABEL = i18n.translate('xpack.ml.explorer.jobIdLabel', * aggregations on influencers values. */ export const ANOMALY_SWIM_LANE_HARD_LIMIT = 1000; + +export const RESIZE_IGNORED_DIFF_PX = 20; diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/clear_influencer_filter_settings.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/clear_influencer_filter_settings.ts index 1614da14e355a45..dd1d0516b6173fc 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/clear_influencer_filter_settings.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/clear_influencer_filter_settings.ts @@ -19,5 +19,6 @@ export function clearInfluencerFilterSettings(state: ExplorerState): ExplorerSta queryString: '', tableQueryString: '', ...getClearedSelectedAnomaliesState(), + viewByFromPage: 1, }; } diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/job_selection_change.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/job_selection_change.ts index a26c0564c6b16d3..49f5794273a04d0 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/job_selection_change.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/job_selection_change.ts @@ -17,6 +17,7 @@ export const jobSelectionChange = (state: ExplorerState, payload: ActionPayload) noInfluencersConfigured: getInfluencers(selectedJobs).length === 0, overallSwimlaneData: getDefaultSwimlaneData(), selectedJobs, + viewByFromPage: 1, }; // clear filter if selected jobs have no influencers diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts index 0bff88688567e32..8f0ba5ebc4f66c1 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts @@ -39,6 +39,7 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo ...state, ...getClearedSelectedAnomaliesState(), loading: false, + viewByFromPage: 1, selectedJobs: [], }; break; @@ -102,6 +103,8 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo ...getClearedSelectedAnomaliesState(), maskAll, viewBySwimlaneFieldName, + viewBySwimlaneData: getDefaultSwimlaneData(), + viewByFromPage: 1, }; break; @@ -129,6 +132,8 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo case EXPLORER_ACTION.SET_VIEW_BY_PER_PAGE: nextState = { ...state, + // reset current page on the page size change + viewByFromPage: 1, viewByPerPage: payload, }; break; diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/set_influencer_filter_settings.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/set_influencer_filter_settings.ts index 819f6ca1cac922e..be87de7da8c883f 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/set_influencer_filter_settings.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/set_influencer_filter_settings.ts @@ -57,5 +57,6 @@ export function setInfluencerFilterSettings( filteredFields.includes(selectedViewByFieldName) === false, viewBySwimlaneFieldName: selectedViewByFieldName, viewBySwimlaneOptions: filteredViewBySwimlaneOptions, + viewByFromPage: 1, }; } diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index f30f1be0c51d34a..0e9c948613cadf8 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -5,7 +5,13 @@ */ import React, { FC, useCallback, useState } from 'react'; -import { EuiResizeObserver, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiLoadingChart, + EuiResizeObserver, + EuiText, +} from '@elastic/eui'; import { throttle } from 'lodash'; import { @@ -15,7 +21,7 @@ import { import { MlTooltipComponent } from '../../application/components/chart_tooltip'; import { SwimLanePagination } from './swimlane_pagination'; -import { SWIMLANE_TYPE } from './explorer_constants'; +import { RESIZE_IGNORED_DIFF_PX, SWIMLANE_TYPE } from './explorer_constants'; import { ViewBySwimLaneData } from './explorer_utils'; const RESIZE_THROTTLE_TIME_MS = 500; @@ -36,12 +42,29 @@ export const SwimlaneContainer: FC< const resizeHandler = useCallback( throttle((e: { width: number; height: number }) => { const labelWidth = 200; - setChartWidth(e.width - labelWidth); - onResize(e.width); + const resultNewWidth = e.width - labelWidth; + if (Math.abs(resultNewWidth - chartWidth) > RESIZE_IGNORED_DIFF_PX) { + setChartWidth(resultNewWidth); + onResize(resultNewWidth); + } }, RESIZE_THROTTLE_TIME_MS), - [] + [chartWidth] ); + const showSwimlane = + props.swimlaneData !== null && + props.swimlaneData.laneLabels && + props.swimlaneData.laneLabels.length > 0; + + const isPaginationVisible = + (props.swimlaneType === SWIMLANE_TYPE.VIEW_BY && + isViewBySwimLaneData(props.swimlaneData) && + fromPage && + perPage && + // only render pagination when there is more than 1 page + props.swimlaneData.cardinality > perPage * fromPage) || + (fromPage && fromPage > 1); + return ( <> @@ -53,21 +76,29 @@ export const SwimlaneContainer: FC< >
- - {(tooltipService) => ( - - )} - + {showSwimlane ? ( + + {(tooltipService) => ( + + )} + + ) : ( + + + + + + )}
)}
- {props.swimlaneType === SWIMLANE_TYPE.VIEW_BY && isViewBySwimLaneData(props.swimlaneData) && ( + {isPaginationVisible && ( = ({ jobsWithTim undefined; useEffect(() => { - loadExplorerData({ - ...loadExplorerDataConfig, - swimlaneLimit: - explorerState?.viewBySwimlaneData && - isViewBySwimLaneData(explorerState?.viewBySwimlaneData) && - explorerState?.viewBySwimlaneData.cardinality, - }); + if (explorerState && explorerState.swimlaneContainerWidth > 0) { + loadExplorerData({ + ...loadExplorerDataConfig, + swimlaneLimit: + explorerState?.viewBySwimlaneData && + isViewBySwimLaneData(explorerState?.viewBySwimlaneData) + ? explorerState?.viewBySwimlaneData.cardinality + : undefined, + }); + } }, [JSON.stringify(loadExplorerDataConfig)]); if (explorerState === undefined || refresh === undefined || showCharts === undefined) {