diff --git a/x-pack/legacy/plugins/ml/public/overview/components/_index.scss b/x-pack/legacy/plugins/ml/public/overview/components/_index.scss index e7c39544da45bf..75ae4ba49bd92f 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/_index.scss +++ b/x-pack/legacy/plugins/ml/public/overview/components/_index.scss @@ -2,10 +2,23 @@ padding-top: 0; } +.mlOverviewPanel__isLoading { + text-align: center; + padding: 10%; +} + .mlOverviewPanel__buttons { float: right; } +.mlOverviewPanel__spinner { + display: inline-block; +} + +.mlOverviewPanel__refreshButton { + padding-right: $euiSizeM; +} + .mlOverviewPanel__statsBar { margin-top: 0; margin-right: 0 diff --git a/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_panel.tsx b/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_panel.tsx index d45a137d9e9a3e..a29d7a0f3e4501 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_panel.tsx +++ b/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_panel.tsx @@ -52,10 +52,15 @@ export const AnalyticsPanel: FC = () => { ); + const panelClass = isInitialized === false ? 'mlOverviewPanel__isLoading' : 'mlOverviewPanel'; + return ( - + {typeof errorMessage !== 'undefined' && errorDisplay} - {isInitialized === false && }      + {isInitialized === false && ( + + )} +      {isInitialized === true && analytics.length === 0 && ( {
- + {i18n.translate('xpack.ml.overview.analyticsList.refreshJobsButtonText', { defaultMessage: 'Refresh', })} diff --git a/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_stats_bar.tsx b/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_stats_bar.tsx index d3360b60f7e538..63d363e2f5a4da 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_stats_bar.tsx +++ b/x-pack/legacy/plugins/ml/public/overview/components/analytics_panel/analytics_stats_bar.tsx @@ -22,8 +22,8 @@ function getAnalyticsStats(analyticsList: any[]) { show: true, }, started: { - label: i18n.translate('xpack.ml.overview.statsBar.startedAnalyticsLabel', { - defaultMessage: 'Started', + label: i18n.translate('xpack.ml.overview.statsBar.runningAnalyticsLabel', { + defaultMessage: 'Running', }), value: 0, show: true, diff --git a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx index bb1a2a6c68e92b..3517c86a6109fc 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx +++ b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx @@ -98,7 +98,7 @@ export const AnomalyDetectionPanel: FC = () => { return ml.results.getMaxAnomalyScore(group.jobIds, twentyFourHoursAgo, latestTimestamp); }); - const results = await Promise.all(promises); + const results = await Promise.all(promises.map(p => p.catch(() => undefined))); const tempGroups = { ...groupsObject }; // Check results for each group's promise index and update state Object.keys(scores).forEach(groupId => { @@ -143,10 +143,12 @@ export const AnomalyDetectionPanel: FC = () => { ); + const panelClass = isLoading ? 'mlOverviewPanel__isLoading' : 'mlOverviewPanel'; + return ( - + {typeof errorMessage !== 'undefined' && errorDisplay} - {isLoading && }    + {isLoading && }    {isLoading === false && typeof errorMessage === 'undefined' && groupsCount === 0 && ( {
- + {i18n.translate('xpack.ml.overview.anomalyDetection.refreshJobsButtonText', { defaultMessage: 'Refresh', })} diff --git a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/table.tsx b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/table.tsx index a9c5ae0e5f31b1..853b33618181f0 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/table.tsx +++ b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/table.tsx @@ -9,9 +9,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiHealth, + EuiIcon, EuiLoadingSpinner, EuiSpacer, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { @@ -40,6 +42,7 @@ export enum AnomalyDetectionListColumns { jobIds = 'jobIds', latestTimestamp = 'latest_timestamp', docsProcessed = 'docs_processed', + jobsInGroup = 'jobs_in_group', } interface Props { @@ -70,13 +73,40 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData }, { field: AnomalyDetectionListColumns.maxAnomalyScore, - name: i18n.translate('xpack.ml.overview.anomalyDetection.tableMaxScore', { - defaultMessage: 'Max anomaly score', - }), + name: ( + + + {i18n.translate('xpack.ml.overview.anomalyDetection.tableMaxScore', { + defaultMessage: 'Max anomaly score', + })}{' '} + + + + ), sortable: true, render: (score: Group['max_anomaly_score']) => { if (score === null) { + // score is not loaded yet return ; + } else if (score === undefined) { + // an error occurred for this group's score + return ( + + + + ); } else { const color: string = getSeverityColor(score); return ( @@ -91,11 +121,10 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData width: '150px', }, { - field: AnomalyDetectionListColumns.jobIds, + field: AnomalyDetectionListColumns.jobsInGroup, name: i18n.translate('xpack.ml.overview.anomalyDetection.tableNumJobs', { defaultMessage: 'Jobs in group', }), - render: (jobIds: Group['jobIds']) => jobIds.length, sortable: true, truncateText: true, width: '100px', @@ -127,6 +156,7 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData }), render: (group: Group) => , width: '100px', + align: 'right', }, ]; diff --git a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/utils.ts b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/utils.ts index f33b60853ea66e..db369d9228e6c7 100644 --- a/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/utils.ts +++ b/x-pack/legacy/plugins/ml/public/overview/components/anomaly_detection_panel/utils.ts @@ -19,6 +19,7 @@ export function getGroupsFromJobs( docs_processed: 0, latest_timestamp: 0, max_anomaly_score: null, + jobs_in_group: 0, }, }; @@ -33,10 +34,12 @@ export function getGroupsFromJobs( docs_processed: job.processed_record_count, latest_timestamp: job.latestTimestampMs, max_anomaly_score: null, + jobs_in_group: 1, }; } else { groups[g].jobIds.push(job.id); groups[g].docs_processed += job.processed_record_count; + groups[g].jobs_in_group++; // if incoming job latest timestamp is greater than the last saved one, replace it if (groups[g].latest_timestamp === undefined) { groups[g].latest_timestamp = job.latestTimestampMs; @@ -48,6 +51,7 @@ export function getGroupsFromJobs( } else { groups.ungrouped.jobIds.push(job.id); groups.ungrouped.docs_processed += job.processed_record_count; + groups.ungrouped.jobs_in_group++; // if incoming job latest timestamp is greater than the last saved one, replace it if (job.latestTimestampMs > groups.ungrouped.latest_timestamp) { groups.ungrouped.latest_timestamp = job.latestTimestampMs;