+
{this._renderTopNav()}
{`screenTitle placeholder`}
- {
- newFilters.forEach((filter) => {
- filter.$state = { store: esFilters.FilterStateStore.APP_STATE };
- });
- this._onFiltersChange([...filters, ...newFilters]);
- }}
- />
+
) : null;
diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts
index e082398a02a9e..40ffda3f31c26 100644
--- a/x-pack/plugins/maps/public/selectors/map_selectors.ts
+++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts
@@ -52,7 +52,6 @@ import { ISource } from '../classes/sources/source';
import { ITMSSource } from '../classes/sources/tms_source';
import { IVectorSource } from '../classes/sources/vector_source';
import { ILayer } from '../classes/layers/layer';
-import { ISavedGisMap } from '../routing/bootstrap/services/saved_gis_map';
function createLayerInstance(
layerDescriptor: LayerDescriptor,
@@ -298,6 +297,10 @@ export const getLayerList = createSelector(
}
);
+export const getLayerListConfigOnly = createSelector(getLayerListRaw, (layerDescriptorList) => {
+ return copyPersistentState(layerDescriptorList);
+});
+
export function getLayerById(layerId: string | null, state: MapStoreState): ILayer | undefined {
return getLayerList(state).find((layer) => {
return layerId === layer.getId();
@@ -417,22 +420,3 @@ export const areLayersLoaded = createSelector(
return true;
}
);
-
-export function hasUnsavedChanges(
- state: MapStoreState,
- savedMap: ISavedGisMap,
- initialLayerListConfig: LayerDescriptor[]
-) {
- const layerListConfigOnly = copyPersistentState(getLayerListRaw(state));
-
- const savedLayerList = savedMap.getLayerList();
-
- return !savedLayerList
- ? !_.isEqual(layerListConfigOnly, initialLayerListConfig)
- : // savedMap stores layerList as a JSON string using JSON.stringify.
- // JSON.stringify removes undefined properties from objects.
- // savedMap.getLayerList converts the JSON string back into Javascript array of objects.
- // Need to perform the same process for layerListConfigOnly to compare apples to apples
- // and avoid undefined properties in layerListConfigOnly triggering unsaved changes.
- !_.isEqual(JSON.parse(JSON.stringify(layerListConfigOnly)), savedLayerList);
-}
diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts
index bb0e351ebfec8..8e6933ed5924f 100644
--- a/x-pack/plugins/ml/common/util/job_utils.ts
+++ b/x-pack/plugins/ml/common/util/job_utils.ts
@@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import isEmpty from 'lodash/isEmpty';
+import isEqual from 'lodash/isEqual';
+import each from 'lodash/each';
+import pick from 'lodash/pick';
+
import semver from 'semver';
import moment, { Duration } from 'moment';
// @ts-ignore
@@ -307,7 +311,7 @@ export function getSafeAggregationName(fieldName: string, index: number): string
export function uniqWithIsEqual
(arr: T): T {
return arr.reduce((dedupedArray, value) => {
- if (dedupedArray.filter((compareValue: any) => _.isEqual(compareValue, value)).length === 0) {
+ if (dedupedArray.filter((compareValue: any) => isEqual(compareValue, value)).length === 0) {
dedupedArray.push(value);
}
return dedupedArray;
@@ -328,7 +332,7 @@ export function basicJobValidation(
if (job) {
// Job details
- if (_.isEmpty(job.job_id)) {
+ if (isEmpty(job.job_id)) {
messages.push({ id: 'job_id_empty' });
valid = false;
} else if (isJobIdValid(job.job_id) === false) {
@@ -350,7 +354,7 @@ export function basicJobValidation(
// Analysis Configuration
if (job.analysis_config.categorization_filters) {
let v = true;
- _.each(job.analysis_config.categorization_filters, (d) => {
+ each(job.analysis_config.categorization_filters, (d) => {
try {
new RegExp(d);
} catch (e) {
@@ -382,8 +386,8 @@ export function basicJobValidation(
valid = false;
} else {
let v = true;
- _.each(job.analysis_config.detectors, (d) => {
- if (_.isEmpty(d.function)) {
+ each(job.analysis_config.detectors, (d) => {
+ if (isEmpty(d.function)) {
v = false;
}
});
@@ -400,7 +404,7 @@ export function basicJobValidation(
// create an array of objects with a subset of the attributes
// where we want to make sure they are not be the same across detectors
const compareSubSet = job.analysis_config.detectors.map((d) =>
- _.pick(d, [
+ pick(d, [
'function',
'field_name',
'by_field_name',
diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
index 69f7635a66032..c6ca4fb821984 100644
--- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
+++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
@@ -9,7 +9,9 @@
* This version supports both fetching the annotations by itself (used in the jobs list) and
* getting the annotations via props (used in Anomaly Explorer and Single Series Viewer).
*/
-import _ from 'lodash';
+
+import uniq from 'lodash/uniq';
+
import PropTypes from 'prop-types';
import rison from 'rison-node';
import React, { Component, Fragment } from 'react';
@@ -255,18 +257,18 @@ export class AnnotationsTable extends Component {
// if the annotation is at the series level
// then pass the partitioning field(s) and detector index to the Single Metric Viewer
- if (_.has(annotation, 'detector_index')) {
+ if (annotation.detector_index !== undefined) {
mlTimeSeriesExplorer.detectorIndex = annotation.detector_index;
}
- if (_.has(annotation, 'partition_field_value')) {
+ if (annotation.partition_field_value !== undefined) {
entityCondition[annotation.partition_field_name] = annotation.partition_field_value;
}
- if (_.has(annotation, 'over_field_value')) {
+ if (annotation.over_field_value !== undefined) {
entityCondition[annotation.over_field_name] = annotation.over_field_value;
}
- if (_.has(annotation, 'by_field_value')) {
+ if (annotation.by_field_value !== undefined) {
// Note that analyses with by and over fields, will have a top-level by_field_name,
// but the by_field_value(s) will be in the nested causes array.
entityCondition[annotation.by_field_name] = annotation.by_field_value;
@@ -421,7 +423,7 @@ export class AnnotationsTable extends Component {
},
];
- const jobIds = _.uniq(annotations.map((a) => a.job_id));
+ const jobIds = uniq(annotations.map((a) => a.job_id));
if (jobIds.length > 1) {
columns.unshift({
field: 'job_id',
diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js
index 2a890f75fecd8..378ee82805173 100644
--- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js
+++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table.js
@@ -9,7 +9,7 @@
*/
import PropTypes from 'prop-types';
-import _ from 'lodash';
+import get from 'lodash/get';
import React, { Component } from 'react';
@@ -70,7 +70,7 @@ class AnomaliesTable extends Component {
} else {
const examples =
item.entityName === 'mlcategory'
- ? _.get(this.props.tableData, ['examplesByJobId', item.jobId, item.entityValue])
+ ? get(this.props.tableData, ['examplesByJobId', item.jobId, item.entityValue])
: undefined;
let definition = undefined;
diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_columns.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_columns.js
index af7c6c8e289f3..57f3a08713ffe 100644
--- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_columns.js
+++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomalies_table_columns.js
@@ -7,7 +7,7 @@
import { EuiButtonIcon, EuiLink, EuiScreenReaderOnly } from '@elastic/eui';
import React from 'react';
-import _ from 'lodash';
+import get from 'lodash/get';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -251,7 +251,7 @@ export function getColumns(
sortable: false,
truncateText: true,
render: (item) => {
- const examples = _.get(examplesByJobId, [item.jobId, item.entityValue], []);
+ const examples = get(examplesByJobId, [item.jobId, item.entityValue], []);
return (
{
- const simplified = _.pick(cause, 'typical', 'actual', 'probability');
+ const simplified = pick(cause, 'typical', 'actual', 'probability');
// Get the 'entity field name/value' to display in the cause -
// For by and over, use by_field_name/value (over_field_name/value are in the top level fields)
// For just an 'over' field - the over_field_name/value appear in both top level and cause.
- simplified.entityName = _.has(cause, 'by_field_name')
- ? cause.by_field_name
- : cause.over_field_name;
- simplified.entityValue = _.has(cause, 'by_field_value')
- ? cause.by_field_value
- : cause.over_field_value;
+ simplified.entityName = cause.by_field_name ? cause.by_field_name : cause.over_field_name;
+ simplified.entityValue = cause.by_field_value ? cause.by_field_value : cause.over_field_value;
return simplified;
});
}
@@ -471,7 +468,7 @@ export class AnomalyDetails extends Component {
renderDetails() {
const detailItems = getDetailsItems(this.props.anomaly, this.props.examples, this.props.filter);
- const isInterimResult = _.get(this.props.anomaly, 'source.is_interim', false);
+ const isInterimResult = get(this.props.anomaly, 'source.is_interim', false);
return (
diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/influencers_cell.js b/x-pack/plugins/ml/public/application/components/anomalies_table/influencers_cell.js
index 2e42606c048d7..abdb0961351ab 100644
--- a/x-pack/plugins/ml/public/application/components/anomalies_table/influencers_cell.js
+++ b/x-pack/plugins/ml/public/application/components/anomalies_table/influencers_cell.js
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import each from 'lodash/each';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
@@ -148,7 +148,7 @@ export class InfluencersCell extends Component {
const influencers = [];
recordInfluencers.forEach((influencer) => {
- _.each(influencer, (influencerFieldValue, influencerFieldName) => {
+ each(influencer, (influencerFieldValue, influencerFieldName) => {
influencers.push({
influencerFieldName,
influencerFieldValue,
diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js
index f603264896cd3..0e4d736a01e47 100644
--- a/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js
+++ b/x-pack/plugins/ml/public/application/components/anomalies_table/links_menu.js
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
import moment from 'moment';
import rison from 'rison-node';
import PropTypes from 'prop-types';
@@ -58,7 +58,7 @@ class LinksMenuUI extends Component {
// If url_value contains $earliest$ and $latest$ tokens, add in times to the source record.
// Create a copy of the record as we are adding properties into it.
- const record = _.cloneDeep(anomaly.source);
+ const record = cloneDeep(anomaly.source);
const timestamp = record.timestamp;
const configuredUrlValue = customUrl.url_value;
const timeRangeInterval = parseInterval(customUrl.time_range);
@@ -99,7 +99,7 @@ class LinksMenuUI extends Component {
if (
(configuredUrlValue.includes('$mlcategoryterms$') ||
configuredUrlValue.includes('$mlcategoryregex$')) &&
- _.has(record, 'mlcategory')
+ record.mlcategory !== undefined
) {
const jobId = record.job_id;
@@ -156,15 +156,15 @@ class LinksMenuUI extends Component {
// Extract the by, over and partition fields for the record.
const entityCondition = {};
- if (_.has(record, 'partition_field_value')) {
+ if (record.partition_field_value !== undefined) {
entityCondition[record.partition_field_name] = record.partition_field_value;
}
- if (_.has(record, 'over_field_value')) {
+ if (record.over_field_value !== undefined) {
entityCondition[record.over_field_name] = record.over_field_value;
}
- if (_.has(record, 'by_field_value')) {
+ if (record.by_field_value !== undefined) {
// Note that analyses with by and over fields, will have a top-level by_field_name,
// but the by_field_value(s) will be in the nested causes array.
// TODO - drilldown from cause in expanded row only?
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_config_builder.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_config_builder.js
index b5e9daad7d1c1..b75784c95c520 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_config_builder.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_config_builder.js
@@ -9,8 +9,6 @@
* the raw data in the Explorer dashboard.
*/
-import _ from 'lodash';
-
import { parseInterval } from '../../../../common/util/parse_interval';
import { getEntityFieldList } from '../../../../common/util/anomaly_utils';
import { buildConfigFromDetector } from '../../util/chart_config_builder';
@@ -30,7 +28,7 @@ export function buildConfig(record) {
config.detectorLabel = record.function;
if (
- _.has(mlJobService.detectorsByJob, record.job_id) &&
+ mlJobService.detectorsByJob[record.job_id] !== undefined &&
detectorIndex < mlJobService.detectorsByJob[record.job_id].length
) {
config.detectorLabel =
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js
index 7a18914957ba9..00aca5d43be85 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js
@@ -11,8 +11,8 @@
import PropTypes from 'prop-types';
import React from 'react';
+import { i18n } from '@kbn/i18n';
-import _ from 'lodash';
import d3 from 'd3';
import $ from 'jquery';
import moment from 'moment';
@@ -33,8 +33,6 @@ import { mlFieldFormatService } from '../../services/field_format_service';
import { CHART_TYPE } from '../explorer_constants';
-import { i18n } from '@kbn/i18n';
-
const CONTENT_WRAPPER_HEIGHT = 215;
// If a rare/event-distribution chart has a cardinality of 10 or less,
@@ -403,7 +401,7 @@ export class ExplorerChartDistribution extends React.Component {
.attr('cy', (d) => lineChartYScale(d[CHART_Y_ATTRIBUTE]))
.attr('class', (d) => {
let markerClass = 'metric-value';
- if (_.has(d, 'anomalyScore') && Number(d.anomalyScore) >= severity) {
+ if (d.anomalyScore !== undefined && Number(d.anomalyScore) >= severity) {
markerClass += ' anomaly-marker ';
markerClass += getSeverityWithLow(d.anomalyScore).id;
}
@@ -444,7 +442,7 @@ export class ExplorerChartDistribution extends React.Component {
const tooltipData = [{ label: formattedDate }];
const seriesKey = config.detectorLabel;
- if (_.has(marker, 'entity')) {
+ if (marker.entity !== undefined) {
tooltipData.push({
label: i18n.translate('xpack.ml.explorer.distributionChart.entityLabel', {
defaultMessage: 'entity',
@@ -457,7 +455,7 @@ export class ExplorerChartDistribution extends React.Component {
});
}
- if (_.has(marker, 'anomalyScore')) {
+ if (marker.anomalyScore !== undefined) {
const score = parseInt(marker.anomalyScore);
const displayScore = score > 0 ? score : '< 1';
tooltipData.push({
@@ -494,7 +492,7 @@ export class ExplorerChartDistribution extends React.Component {
valueAccessor: 'typical',
});
}
- if (typeof marker.byFieldName !== 'undefined' && _.has(marker, 'numberOfCauses')) {
+ if (typeof marker.byFieldName !== 'undefined' && marker.numberOfCauses !== undefined) {
tooltipData.push({
label: i18n.translate(
'xpack.ml.explorer.distributionChart.unusualByFieldValuesLabel',
@@ -532,7 +530,7 @@ export class ExplorerChartDistribution extends React.Component {
});
}
- if (_.has(marker, 'scheduledEvents')) {
+ if (marker.scheduledEvents !== undefined) {
marker.scheduledEvents.forEach((scheduledEvent, i) => {
tooltipData.push({
label: i18n.translate(
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js
index 63775c5ca312e..4d53e747d4855 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js
@@ -12,10 +12,10 @@
import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'lodash';
import d3 from 'd3';
import $ from 'jquery';
import moment from 'moment';
+import { i18n } from '@kbn/i18n';
import { formatHumanReadableDateTime } from '../../util/date_utils';
import { formatValue } from '../../formatters/format_value';
@@ -40,8 +40,6 @@ import { getTimeBucketsFromCache } from '../../util/time_buckets';
import { mlEscape } from '../../util/string_utils';
import { mlFieldFormatService } from '../../services/field_format_service';
-import { i18n } from '@kbn/i18n';
-
const CONTENT_WRAPPER_HEIGHT = 215;
const CONTENT_WRAPPER_CLASS = 'ml-explorer-chart-content-wrapper';
@@ -307,7 +305,7 @@ export class ExplorerChartSingleMetric extends React.Component {
.on('mouseout', () => tooltipService.hide());
const isAnomalyVisible = (d) =>
- _.has(d, 'anomalyScore') && Number(d.anomalyScore) >= severity;
+ d.anomalyScore !== undefined && Number(d.anomalyScore) >= severity;
// Update all dots to new positions.
dots
@@ -380,7 +378,7 @@ export class ExplorerChartSingleMetric extends React.Component {
const tooltipData = [{ label: formattedDate }];
const seriesKey = config.detectorLabel;
- if (_.has(marker, 'anomalyScore')) {
+ if (marker.anomalyScore !== undefined) {
const score = parseInt(marker.anomalyScore);
const displayScore = score > 0 ? score : '< 1';
tooltipData.push({
@@ -411,7 +409,7 @@ export class ExplorerChartSingleMetric extends React.Component {
// Show actual/typical when available except for rare detectors.
// Rare detectors always have 1 as actual and the probability as typical.
// Exposing those values in the tooltip with actual/typical labels might irritate users.
- if (_.has(marker, 'actual') && config.functionDescription !== 'rare') {
+ if (marker.actual !== undefined && config.functionDescription !== 'rare') {
// Display the record actual in preference to the chart value, which may be
// different depending on the aggregation interval of the chart.
tooltipData.push({
@@ -445,7 +443,7 @@ export class ExplorerChartSingleMetric extends React.Component {
},
valueAccessor: 'value',
});
- if (_.has(marker, 'byFieldName') && _.has(marker, 'numberOfCauses')) {
+ if (marker.byFieldName !== undefined && marker.numberOfCauses !== undefined) {
tooltipData.push({
label: i18n.translate(
'xpack.ml.explorer.distributionChart.unusualByFieldValuesLabel',
@@ -483,7 +481,7 @@ export class ExplorerChartSingleMetric extends React.Component {
});
}
- if (_.has(marker, 'scheduledEvents')) {
+ if (marker.scheduledEvents !== undefined) {
tooltipData.push({
label: i18n.translate('xpack.ml.explorer.singleMetricChart.scheduledEventsLabel', {
defaultMessage: 'Scheduled events',
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js
index 1b83a4ed30560..712b64af2db80 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js
@@ -11,7 +11,12 @@
* and manages the layout of the charts in the containing div.
*/
-import _ from 'lodash';
+import get from 'lodash/get';
+import each from 'lodash/each';
+import find from 'lodash/find';
+import sortBy from 'lodash/sortBy';
+import map from 'lodash/map';
+import reduce from 'lodash/reduce';
import { buildConfig } from './explorer_chart_config_builder';
import { chartLimits, getChartType } from '../../util/chart_utils';
@@ -113,7 +118,7 @@ export const anomalyDataChange = function (
// If source data can be plotted, use that, otherwise model plot will be available.
const useSourceData = isSourceDataChartableForDetector(job, detectorIndex);
if (useSourceData === true) {
- const datafeedQuery = _.get(config, 'datafeedConfig.query', null);
+ const datafeedQuery = get(config, 'datafeedConfig.query', null);
return mlResultsService
.getMetricData(
config.datafeedConfig.indices,
@@ -131,8 +136,8 @@ export const anomalyDataChange = function (
// Extract the partition, by, over fields on which to filter.
const criteriaFields = [];
const detector = job.analysis_config.detectors[detectorIndex];
- if (_.has(detector, 'partition_field_name')) {
- const partitionEntity = _.find(entityFields, {
+ if (detector.partition_field_name !== undefined) {
+ const partitionEntity = find(entityFields, {
fieldName: detector.partition_field_name,
});
if (partitionEntity !== undefined) {
@@ -143,8 +148,8 @@ export const anomalyDataChange = function (
}
}
- if (_.has(detector, 'over_field_name')) {
- const overEntity = _.find(entityFields, { fieldName: detector.over_field_name });
+ if (detector.over_field_name !== undefined) {
+ const overEntity = find(entityFields, { fieldName: detector.over_field_name });
if (overEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'over_field_name', fieldValue: overEntity.fieldName },
@@ -153,8 +158,8 @@ export const anomalyDataChange = function (
}
}
- if (_.has(detector, 'by_field_name')) {
- const byEntity = _.find(entityFields, { fieldName: detector.by_field_name });
+ if (detector.by_field_name !== undefined) {
+ const byEntity = find(entityFields, { fieldName: detector.by_field_name });
if (byEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'by_field_name', fieldValue: byEntity.fieldName },
@@ -236,7 +241,7 @@ export const anomalyDataChange = function (
filterField = config.entityFields.find((f) => f.fieldType === 'partition');
}
- const datafeedQuery = _.get(config, 'datafeedConfig.query', null);
+ const datafeedQuery = get(config, 'datafeedConfig.query', null);
return mlResultsService.getEventDistributionData(
config.datafeedConfig.indices,
splitField,
@@ -285,7 +290,7 @@ export const anomalyDataChange = function (
if (eventDistribution.length > 0 && records.length > 0) {
const filterField = records[0].by_field_value || records[0].over_field_value;
chartData = eventDistribution.filter((d) => d.entity !== filterField);
- _.map(metricData, (value, time) => {
+ map(metricData, (value, time) => {
// The filtering for rare/event_distribution charts needs to be handled
// differently because of how the source data is structured.
// For rare chart values we are only interested wether a value is either `0` or not,
@@ -304,7 +309,7 @@ export const anomalyDataChange = function (
}
});
} else {
- chartData = _.map(metricData, (value, time) => ({
+ chartData = map(metricData, (value, time) => ({
date: +time,
value: value,
}));
@@ -314,7 +319,7 @@ export const anomalyDataChange = function (
// Iterate through the anomaly records, adding anomalyScore properties
// to the chartData entries for anomalous buckets.
const chartDataForPointSearch = getChartDataForPointSearch(chartData, records[0], chartType);
- _.each(records, (record) => {
+ each(records, (record) => {
// Look for a chart point with the same time as the record.
// If none found, insert a point for anomalies due to a gap in the data.
const recordTime = record[ML_TIME_FIELD_NAME];
@@ -330,13 +335,13 @@ export const anomalyDataChange = function (
chartPoint.actual = record.actual;
chartPoint.typical = record.typical;
} else {
- const causes = _.get(record, 'causes', []);
+ const causes = get(record, 'causes', []);
if (causes.length > 0) {
chartPoint.byFieldName = record.by_field_name;
chartPoint.numberOfCauses = causes.length;
if (causes.length === 1) {
// If only a single cause, copy actual and typical values to the top level.
- const cause = _.first(record.causes);
+ const cause = record.causes[0];
chartPoint.actual = cause.actual;
chartPoint.typical = cause.typical;
}
@@ -351,7 +356,7 @@ export const anomalyDataChange = function (
// Add a scheduledEvents property to any points in the chart data set
// which correspond to times of scheduled events for the job.
if (scheduledEvents !== undefined) {
- _.each(scheduledEvents, (events, time) => {
+ each(scheduledEvents, (events, time) => {
const chartPoint = findChartPointForTime(chartDataForPointSearch, Number(time));
if (chartPoint !== undefined) {
// Note if the scheduled event coincides with an absence of the underlying metric data,
@@ -385,10 +390,10 @@ export const anomalyDataChange = function (
.then((response) => {
// calculate an overall min/max for all series
const processedData = response.map(processChartData);
- const allDataPoints = _.reduce(
+ const allDataPoints = reduce(
processedData,
(datapoints, series) => {
- _.each(series, (d) => datapoints.push(d));
+ each(series, (d) => datapoints.push(d));
return datapoints;
},
[]
@@ -420,7 +425,7 @@ function processRecordsForDisplay(anomalyRecords) {
// Aggregate by job, detector, and analysis fields (partition, by, over).
const aggregatedData = {};
- _.each(anomalyRecords, (record) => {
+ each(anomalyRecords, (record) => {
// Check if we can plot a chart for this record, depending on whether the source data
// is chartable, and if model plot is enabled for the job.
const job = mlJobService.getJob(record.job_id);
@@ -524,20 +529,20 @@ function processRecordsForDisplay(anomalyRecords) {
let recordsForSeries = [];
// Convert to an array of the records with the highest record_score per unique series.
- _.each(aggregatedData, (detectorsForJob) => {
- _.each(detectorsForJob, (groupsForDetector) => {
+ each(aggregatedData, (detectorsForJob) => {
+ each(detectorsForJob, (groupsForDetector) => {
if (groupsForDetector.maxScoreRecord !== undefined) {
// Detector with no partition / by field.
recordsForSeries.push(groupsForDetector.maxScoreRecord);
} else {
- _.each(groupsForDetector, (valuesForGroup) => {
- _.each(valuesForGroup, (dataForGroupValue) => {
+ each(groupsForDetector, (valuesForGroup) => {
+ each(valuesForGroup, (dataForGroupValue) => {
if (dataForGroupValue.maxScoreRecord !== undefined) {
recordsForSeries.push(dataForGroupValue.maxScoreRecord);
} else {
// Second level of aggregation for partition and by/over.
- _.each(dataForGroupValue, (splitsForGroup) => {
- _.each(splitsForGroup, (dataForSplitValue) => {
+ each(dataForGroupValue, (splitsForGroup) => {
+ each(splitsForGroup, (dataForSplitValue) => {
recordsForSeries.push(dataForSplitValue.maxScoreRecord);
});
});
@@ -547,7 +552,7 @@ function processRecordsForDisplay(anomalyRecords) {
}
});
});
- recordsForSeries = _.sortBy(recordsForSeries, 'record_score').reverse();
+ recordsForSeries = sortBy(recordsForSeries, 'record_score').reverse();
return recordsForSeries;
}
@@ -564,7 +569,7 @@ function calculateChartRange(
// Calculate the time range for the charts.
// Fit in as many points in the available container width plotted at the job bucket span.
const midpointMs = Math.ceil((earliestMs + latestMs) / 2);
- const maxBucketSpanMs = Math.max.apply(null, _.map(seriesConfigs, 'bucketSpanSeconds')) * 1000;
+ const maxBucketSpanMs = Math.max.apply(null, map(seriesConfigs, 'bucketSpanSeconds')) * 1000;
const pointsToPlotFullSelection = Math.ceil((latestMs - earliestMs) / maxBucketSpanMs);
@@ -588,7 +593,7 @@ function calculateChartRange(
let minMs = recordsToPlot[0][timeFieldName];
let maxMs = recordsToPlot[0][timeFieldName];
- _.each(recordsToPlot, (record) => {
+ each(recordsToPlot, (record) => {
const diffMs = maxMs - minMs;
if (diffMs < maxTimeSpan) {
const recordTime = record[timeFieldName];
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.test.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.test.js
index 433aa65cc5dd4..a7d422d161108 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.test.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.test.js
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
import mockAnomalyChartRecords from './__mocks__/mock_anomaly_chart_records.json';
import mockDetectorsByJob from './__mocks__/mock_detectors_by_job.json';
@@ -24,10 +24,10 @@ import mockSeriesPromisesResponse from './__mocks__/mock_series_promises_respons
// suitable responses from the mocked services. The mocked services check against the
// provided alternative values and return specific modified mock responses for the test case.
-const mockJobConfigClone = _.cloneDeep(mockJobConfig);
+const mockJobConfigClone = cloneDeep(mockJobConfig);
// adjust mock data to tests against null/0 values
-const mockMetricClone = _.cloneDeep(mockSeriesPromisesResponse[0][0]);
+const mockMetricClone = cloneDeep(mockSeriesPromisesResponse[0][0]);
mockMetricClone.results['1486712700000'] = null;
mockMetricClone.results['1486713600000'] = 0;
@@ -127,7 +127,7 @@ describe('explorerChartsContainerService', () => {
});
test('filtering should skip values of null', (done) => {
- const mockAnomalyChartRecordsClone = _.cloneDeep(mockAnomalyChartRecords).map((d) => {
+ const mockAnomalyChartRecordsClone = cloneDeep(mockAnomalyChartRecords).map((d) => {
d.job_id = 'mock-job-id-distribution';
return d;
});
@@ -151,7 +151,7 @@ describe('explorerChartsContainerService', () => {
});
test('field value with trailing dot should not throw an error', (done) => {
- const mockAnomalyChartRecordsClone = _.cloneDeep(mockAnomalyChartRecords);
+ const mockAnomalyChartRecordsClone = cloneDeep(mockAnomalyChartRecords);
mockAnomalyChartRecordsClone[1].partition_field_value = 'AAL.';
expect(() => {
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_swimlane.tsx b/x-pack/plugins/ml/public/application/explorer/explorer_swimlane.tsx
index 2590ab2f1cb23..05e082711f619 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer_swimlane.tsx
+++ b/x-pack/plugins/ml/public/application/explorer/explorer_swimlane.tsx
@@ -10,7 +10,9 @@
import React from 'react';
import './_explorer.scss';
-import _, { isEqual } from 'lodash';
+import isEqual from 'lodash/isEqual';
+import uniq from 'lodash/uniq';
+import get from 'lodash/get';
import d3 from 'd3';
import moment from 'moment';
import DragSelect from 'dragselect';
@@ -176,9 +178,9 @@ export class ExplorerSwimlane extends React.Component {
}
);
- selectedData.laneLabels = _.uniq(selectedData.laneLabels);
- selectedData.times = _.uniq(selectedData.times);
- if (_.isEqual(selectedData, previousSelectedData) === false) {
+ selectedData.laneLabels = uniq(selectedData.laneLabels);
+ selectedData.times = uniq(selectedData.times);
+ if (isEqual(selectedData, previousSelectedData) === false) {
// If no cells containing anomalies have been selected,
// immediately clear the selection, otherwise trigger
// a reload with the updated selected cells.
@@ -246,7 +248,7 @@ export class ExplorerSwimlane extends React.Component {
selectedTimes: d3.extent(times),
};
- if (_.isEqual(oldSelection, newSelection)) {
+ if (isEqual(oldSelection, newSelection)) {
triggerNewSelection = false;
}
@@ -277,8 +279,8 @@ export class ExplorerSwimlane extends React.Component {
// Check for selection and reselect the corresponding swimlane cell
// if the time range and lane label are still in view.
const selectionState = selection;
- const selectedType = _.get(selectionState, 'type', undefined);
- const selectionViewByFieldName = _.get(selectionState, 'viewByFieldName', '');
+ const selectedType = get(selectionState, 'type', undefined);
+ const selectionViewByFieldName = get(selectionState, 'viewByFieldName', '');
// If a selection was done in the other swimlane, add the "masked" classes
// to de-emphasize the swimlane cells.
@@ -288,8 +290,8 @@ export class ExplorerSwimlane extends React.Component {
}
const cellsToSelect: Node[] = [];
- const selectedLanes = _.get(selectionState, 'lanes', []);
- const selectedTimes = _.get(selectionState, 'times', []);
+ const selectedLanes = get(selectionState, 'lanes', []);
+ const selectedTimes = get(selectionState, 'times', []);
const selectedTimeExtent = d3.extent(selectedTimes);
if (
diff --git a/x-pack/plugins/ml/public/application/services/forecast_service.js b/x-pack/plugins/ml/public/application/services/forecast_service.js
index ed5a29ff74a63..57e50387a03ab 100644
--- a/x-pack/plugins/ml/public/application/services/forecast_service.js
+++ b/x-pack/plugins/ml/public/application/services/forecast_service.js
@@ -6,7 +6,9 @@
// Service for carrying out requests to run ML forecasts and to obtain
// data on forecasts that have been performed.
-import _ from 'lodash';
+import get from 'lodash/get';
+import find from 'lodash/find';
+import each from 'lodash/each';
import { map } from 'rxjs/operators';
import { ml } from './ml_api_service';
@@ -129,8 +131,8 @@ function getForecastDateRange(job, forecastId) {
},
})
.then((resp) => {
- obj.earliest = _.get(resp, 'aggregations.earliest.value', null);
- obj.latest = _.get(resp, 'aggregations.latest.value', null);
+ obj.earliest = get(resp, 'aggregations.earliest.value', null);
+ obj.latest = get(resp, 'aggregations.latest.value', null);
if (obj.earliest === null || obj.latest === null) {
reject(resp);
} else {
@@ -157,8 +159,8 @@ function getForecastData(
// Extract the partition, by, over fields on which to filter.
const criteriaFields = [];
const detector = job.analysis_config.detectors[detectorIndex];
- if (_.has(detector, 'partition_field_name')) {
- const partitionEntity = _.find(entityFields, { fieldName: detector.partition_field_name });
+ if (detector.partition_field_name !== undefined) {
+ const partitionEntity = find(entityFields, { fieldName: detector.partition_field_name });
if (partitionEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'partition_field_name', fieldValue: partitionEntity.fieldName },
@@ -167,8 +169,8 @@ function getForecastData(
}
}
- if (_.has(detector, 'over_field_name')) {
- const overEntity = _.find(entityFields, { fieldName: detector.over_field_name });
+ if (detector.over_field_name !== undefined) {
+ const overEntity = find(entityFields, { fieldName: detector.over_field_name });
if (overEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'over_field_name', fieldValue: overEntity.fieldName },
@@ -177,8 +179,8 @@ function getForecastData(
}
}
- if (_.has(detector, 'by_field_name')) {
- const byEntity = _.find(entityFields, { fieldName: detector.by_field_name });
+ if (detector.by_field_name !== undefined) {
+ const byEntity = find(entityFields, { fieldName: detector.by_field_name });
if (byEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'by_field_name', fieldValue: byEntity.fieldName },
@@ -222,7 +224,7 @@ function getForecastData(
];
// Add in term queries for each of the specified criteria.
- _.each(criteriaFields, (criteria) => {
+ each(criteriaFields, (criteria) => {
filterCriteria.push({
term: {
[criteria.fieldName]: criteria.fieldValue,
@@ -281,13 +283,13 @@ function getForecastData(
})
.pipe(
map((resp) => {
- const aggregationsByTime = _.get(resp, ['aggregations', 'times', 'buckets'], []);
- _.each(aggregationsByTime, (dataForTime) => {
+ const aggregationsByTime = get(resp, ['aggregations', 'times', 'buckets'], []);
+ each(aggregationsByTime, (dataForTime) => {
const time = dataForTime.key;
obj.results[time] = {
- prediction: _.get(dataForTime, ['prediction', 'value']),
- forecastUpper: _.get(dataForTime, ['forecastUpper', 'value']),
- forecastLower: _.get(dataForTime, ['forecastLower', 'value']),
+ prediction: get(dataForTime, ['prediction', 'value']),
+ forecastUpper: get(dataForTime, ['forecastUpper', 'value']),
+ forecastLower: get(dataForTime, ['forecastLower', 'value']),
};
});
@@ -355,7 +357,7 @@ function getForecastRequestStats(job, forecastId) {
})
.then((resp) => {
if (resp.hits.total !== 0) {
- obj.stats = _.first(resp.hits.hits)._source;
+ obj.stats = resp.hits.hits[0]._source;
}
resolve(obj);
})
diff --git a/x-pack/plugins/ml/public/application/services/job_service.js b/x-pack/plugins/ml/public/application/services/job_service.js
index 7e90758ffd7db..704d76059f75c 100644
--- a/x-pack/plugins/ml/public/application/services/job_service.js
+++ b/x-pack/plugins/ml/public/application/services/job_service.js
@@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
+import each from 'lodash/each';
+import find from 'lodash/find';
+import get from 'lodash/get';
+import isNumber from 'lodash/isNumber';
import moment from 'moment';
import { i18n } from '@kbn/i18n';
@@ -135,10 +139,10 @@ class JobService {
const jobStats = statsResp.jobs[j];
if (job.job_id === jobStats.job_id) {
job.state = jobStats.state;
- job.data_counts = _.cloneDeep(jobStats.data_counts);
- job.model_size_stats = _.cloneDeep(jobStats.model_size_stats);
+ job.data_counts = cloneDeep(jobStats.data_counts);
+ job.model_size_stats = cloneDeep(jobStats.model_size_stats);
if (jobStats.node) {
- job.node = _.cloneDeep(jobStats.node);
+ job.node = cloneDeep(jobStats.node);
}
if (jobStats.open_time) {
job.open_time = jobStats.open_time;
@@ -212,10 +216,10 @@ class JobService {
newJob.state = statsJob.state;
newJob.data_counts = {};
newJob.model_size_stats = {};
- newJob.data_counts = _.cloneDeep(statsJob.data_counts);
- newJob.model_size_stats = _.cloneDeep(statsJob.model_size_stats);
+ newJob.data_counts = cloneDeep(statsJob.data_counts);
+ newJob.model_size_stats = cloneDeep(statsJob.model_size_stats);
if (newJob.node) {
- newJob.node = _.cloneDeep(statsJob.node);
+ newJob.node = cloneDeep(statsJob.node);
}
if (statsJob.open_time) {
@@ -352,7 +356,7 @@ class JobService {
// create a deep copy of a job object
// also remove items from the job which are set by the server and not needed
// in the future this formatting could be optional
- const tempJob = _.cloneDeep(job);
+ const tempJob = cloneDeep(job);
// remove all of the items which should not be copied
// such as counts, state and times
@@ -375,7 +379,7 @@ class JobService {
delete tempJob.analysis_config.use_per_partition_normalization;
- _.each(tempJob.analysis_config.detectors, (d) => {
+ each(tempJob.analysis_config.detectors, (d) => {
delete d.detector_index;
});
@@ -469,7 +473,7 @@ class JobService {
// find a job based on the id
getJob(jobId) {
- const job = _.find(jobs, (j) => {
+ const job = find(jobs, (j) => {
return j.job_id === jobId;
});
@@ -550,7 +554,7 @@ class JobService {
// get fields from detectors
if (job.analysis_config.detectors) {
- _.each(job.analysis_config.detectors, (dtr) => {
+ each(job.analysis_config.detectors, (dtr) => {
if (dtr.by_field_name) {
fields[dtr.by_field_name] = {};
}
@@ -568,7 +572,7 @@ class JobService {
// get fields from influencers
if (job.analysis_config.influencers) {
- _.each(job.analysis_config.influencers, (inf) => {
+ each(job.analysis_config.influencers, (inf) => {
fields[inf] = {};
});
}
@@ -659,7 +663,7 @@ class JobService {
return new Promise((resolve, reject) => {
// if the end timestamp is a number, add one ms to it to make it
// inclusive of the end of the data
- if (_.isNumber(end)) {
+ if (isNumber(end)) {
end++;
}
@@ -780,7 +784,7 @@ class JobService {
});
}
});
- _.each(tempGroups, (js, id) => {
+ each(tempGroups, (js, id) => {
groups.push({ id, jobs: js });
});
return groups;
@@ -837,9 +841,9 @@ function processBasicJobInfo(localJobService, jobsList) {
const customUrlsByJob = {};
// use cloned copy of jobs list so not to alter the original
- const jobsListCopy = _.cloneDeep(jobsList);
+ const jobsListCopy = cloneDeep(jobsList);
- _.each(jobsListCopy, (jobObj) => {
+ each(jobsListCopy, (jobObj) => {
const analysisConfig = jobObj.analysis_config;
const bucketSpan = parseInterval(analysisConfig.bucket_span);
@@ -848,20 +852,20 @@ function processBasicJobInfo(localJobService, jobsList) {
bucketSpanSeconds: bucketSpan.asSeconds(),
};
- if (_.has(jobObj, 'description') && /^\s*$/.test(jobObj.description) === false) {
+ if (jobObj.description !== undefined && /^\s*$/.test(jobObj.description) === false) {
job.description = jobObj.description;
} else {
// Just use the id as the description.
job.description = jobObj.job_id;
}
- job.detectors = _.get(analysisConfig, 'detectors', []);
+ job.detectors = get(analysisConfig, 'detectors', []);
detectorsByJob[job.id] = job.detectors;
- if (_.has(jobObj, 'custom_settings.custom_urls')) {
+ if (jobObj.custom_settings !== undefined && jobObj.custom_settings.custom_urls !== undefined) {
job.customUrls = [];
- _.each(jobObj.custom_settings.custom_urls, (url) => {
- if (_.has(url, 'url_name') && _.has(url, 'url_value') && isWebUrl(url.url_value)) {
+ each(jobObj.custom_settings.custom_urls, (url) => {
+ if (url.url_name !== undefined && url.url_value !== undefined && isWebUrl(url.url_value)) {
// Only make web URLs (i.e. http or https) available in dashboard drilldowns.
job.customUrls.push(url);
}
@@ -897,7 +901,7 @@ function createJobStats(jobsList, jobStats) {
const mlNodes = {};
let failedJobs = 0;
- _.each(jobsList, (job) => {
+ each(jobsList, (job) => {
if (job.state === 'opened') {
jobStats.open.value++;
} else if (job.state === 'closed') {
diff --git a/x-pack/plugins/ml/public/application/services/mapping_service.js b/x-pack/plugins/ml/public/application/services/mapping_service.js
index 52aa5ed7413cb..251bb0bce5690 100644
--- a/x-pack/plugins/ml/public/application/services/mapping_service.js
+++ b/x-pack/plugins/ml/public/application/services/mapping_service.js
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import each from 'lodash/each';
import { ml } from './ml_api_service';
@@ -16,8 +16,8 @@ export function getFieldTypeFromMapping(index, fieldName) {
ml.getFieldCaps({ index, fields: [fieldName] })
.then((resp) => {
let fieldType = '';
- _.each(resp.fields, (field) => {
- _.each(field, (type) => {
+ each(resp.fields, (field) => {
+ each(field, (type) => {
if (fieldType === '') {
fieldType = type.type;
}
diff --git a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts
index d7f016b419377..898ca8894cbda 100644
--- a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts
+++ b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts
@@ -13,7 +13,8 @@
// Returned response contains a results property containing the requested aggregation.
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
-import _ from 'lodash';
+import each from 'lodash/each';
+import get from 'lodash/get';
import { Dictionary } from '../../../../common/types/common';
import { ML_MEDIAN_PERCENTS } from '../../../../common/util/job_utils';
import { JobId } from '../../../../common/types/anomaly_detection_jobs';
@@ -237,7 +238,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
];
// Add in term queries for each of the specified criteria.
- _.each(criteriaFields, (criteria) => {
+ each(criteriaFields, (criteria) => {
mustCriteria.push({
term: {
[criteria.fieldName]: criteria.fieldValue,
@@ -316,12 +317,12 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
})
.pipe(
map((resp) => {
- const aggregationsByTime = _.get(resp, ['aggregations', 'times', 'buckets'], []);
- _.each(aggregationsByTime, (dataForTime: any) => {
+ const aggregationsByTime = get(resp, ['aggregations', 'times', 'buckets'], []);
+ each(aggregationsByTime, (dataForTime: any) => {
const time = dataForTime.key;
- const modelUpper: number | undefined = _.get(dataForTime, ['modelUpper', 'value']);
- const modelLower: number | undefined = _.get(dataForTime, ['modelLower', 'value']);
- const actual = _.get(dataForTime, ['actual', 'value']);
+ const modelUpper: number | undefined = get(dataForTime, ['modelUpper', 'value']);
+ const modelLower: number | undefined = get(dataForTime, ['modelLower', 'value']);
+ const actual = get(dataForTime, ['actual', 'value']);
obj.results[time] = {
actual,
@@ -375,7 +376,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -391,7 +392,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
}
// Add in term queries for each of the specified criteria.
- _.each(criteriaFields, (criteria) => {
+ each(criteriaFields, (criteria) => {
boolCriteria.push({
term: {
[criteria.fieldName]: criteria.fieldValue,
@@ -428,7 +429,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
.pipe(
map((resp) => {
if (resp.hits.total !== 0) {
- _.each(resp.hits.hits, (hit: any) => {
+ each(resp.hits.hits, (hit: any) => {
obj.records.push(hit._source);
});
}
@@ -473,7 +474,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
jobIdFilterStr += `${i > 0 ? ' OR ' : ''}job_id:${jobId}`;
});
boolCriteria.push({
@@ -536,15 +537,15 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) {
})
.pipe(
map((resp) => {
- const dataByJobId = _.get(resp, ['aggregations', 'jobs', 'buckets'], []);
- _.each(dataByJobId, (dataForJob: any) => {
+ const dataByJobId = get(resp, ['aggregations', 'jobs', 'buckets'], []);
+ each(dataByJobId, (dataForJob: any) => {
const jobId: string = dataForJob.key;
const resultsForTime: Record = {};
- const dataByTime = _.get(dataForJob, ['times', 'buckets'], []);
- _.each(dataByTime, (dataForTime: any) => {
+ const dataByTime = get(dataForJob, ['times', 'buckets'], []);
+ each(dataByTime, (dataForTime: any) => {
const time: string = dataForTime.key;
- const events: object[] = _.get(dataForTime, ['events', 'buckets']);
- resultsForTime[time] = _.map(events, 'key');
+ const events: any[] = get(dataForTime, ['events', 'buckets']);
+ resultsForTime[time] = events.map((e) => e.key);
});
obj.events[jobId] = resultsForTime;
});
diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.js b/x-pack/plugins/ml/public/application/services/results_service/results_service.js
index 50e2d0a5a2a0b..0c3b2e40c8e26 100644
--- a/x-pack/plugins/ml/public/application/services/results_service/results_service.js
+++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.js
@@ -4,7 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import each from 'lodash/each';
+import get from 'lodash/get';
import { ML_MEDIAN_PERCENTS } from '../../../../common/util/job_utils';
import { escapeForElasticsearchQuery } from '../../util/string_utils';
@@ -50,7 +51,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -131,18 +132,18 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const dataByJobId = _.get(resp, ['aggregations', 'jobId', 'buckets'], []);
- _.each(dataByJobId, (dataForJob) => {
+ const dataByJobId = get(resp, ['aggregations', 'jobId', 'buckets'], []);
+ each(dataByJobId, (dataForJob) => {
const jobId = dataForJob.key;
const resultsForTime = {};
- const dataByTime = _.get(dataForJob, ['byTime', 'buckets'], []);
- _.each(dataByTime, (dataForTime) => {
- const value = _.get(dataForTime, ['anomalyScore', 'value']);
+ const dataByTime = get(dataForJob, ['byTime', 'buckets'], []);
+ each(dataByTime, (dataForTime) => {
+ const value = get(dataForTime, ['anomalyScore', 'value']);
if (value !== undefined) {
const time = dataForTime.key;
- resultsForTime[time] = _.get(dataForTime, ['anomalyScore', 'value']);
+ resultsForTime[time] = get(dataForTime, ['anomalyScore', 'value']);
}
});
obj.results[jobId] = resultsForTime;
@@ -198,7 +199,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -305,17 +306,17 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const fieldNameBuckets = _.get(
+ const fieldNameBuckets = get(
resp,
['aggregations', 'influencerFieldNames', 'buckets'],
[]
);
- _.each(fieldNameBuckets, (nameBucket) => {
+ each(fieldNameBuckets, (nameBucket) => {
const fieldName = nameBucket.key;
const fieldValues = [];
- const fieldValueBuckets = _.get(nameBucket, ['influencerFieldValues', 'buckets'], []);
- _.each(fieldValueBuckets, (valueBucket) => {
+ const fieldValueBuckets = get(nameBucket, ['influencerFieldValues', 'buckets'], []);
+ each(fieldValueBuckets, (valueBucket) => {
const fieldValueResult = {
influencerFieldValue: valueBucket.key,
maxAnomalyScore: valueBucket.maxAnomalyScore.value,
@@ -360,7 +361,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -424,8 +425,8 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const buckets = _.get(resp, ['aggregations', 'influencerFieldValues', 'buckets'], []);
- _.each(buckets, (bucket) => {
+ const buckets = get(resp, ['aggregations', 'influencerFieldValues', 'buckets'], []);
+ each(buckets, (bucket) => {
const result = {
influencerFieldValue: bucket.key,
maxAnomalyScore: bucket.maxAnomalyScore.value,
@@ -458,9 +459,9 @@ export function resultsServiceProvider(mlApiServices) {
end: latestMs,
})
.then((resp) => {
- const dataByTime = _.get(resp, ['overall_buckets'], []);
- _.each(dataByTime, (dataForTime) => {
- const value = _.get(dataForTime, ['overall_score']);
+ const dataByTime = get(resp, ['overall_buckets'], []);
+ each(dataByTime, (dataForTime) => {
+ const value = get(dataForTime, ['overall_score']);
if (value !== undefined) {
obj.results[dataForTime.timestamp] = value;
}
@@ -517,7 +518,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -537,7 +538,7 @@ export function resultsServiceProvider(mlApiServices) {
if (influencerFieldValues && influencerFieldValues.length > 0) {
let influencerFilterStr = '';
- _.each(influencerFieldValues, (value, i) => {
+ each(influencerFieldValues, (value, i) => {
if (i > 0) {
influencerFilterStr += ' OR ';
}
@@ -625,17 +626,17 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const fieldValueBuckets = _.get(
+ const fieldValueBuckets = get(
resp,
['aggregations', 'influencerFieldValues', 'buckets'],
[]
);
- _.each(fieldValueBuckets, (valueBucket) => {
+ each(fieldValueBuckets, (valueBucket) => {
const fieldValue = valueBucket.key;
const fieldValues = {};
- const timeBuckets = _.get(valueBucket, ['byTime', 'buckets'], []);
- _.each(timeBuckets, (timeBucket) => {
+ const timeBuckets = get(valueBucket, ['byTime', 'buckets'], []);
+ each(timeBuckets, (timeBucket) => {
const time = timeBucket.key;
const score = timeBucket.maxAnomalyScore.value;
fieldValues[time] = score;
@@ -701,7 +702,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -744,7 +745,7 @@ export function resultsServiceProvider(mlApiServices) {
})
.then((resp) => {
if (resp.hits.total !== 0) {
- _.each(resp.hits.hits, (hit) => {
+ each(resp.hits.hits, (hit) => {
obj.records.push(hit._source);
});
}
@@ -797,7 +798,7 @@ export function resultsServiceProvider(mlApiServices) {
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i) => {
+ each(jobIds, (jobId, i) => {
if (i > 0) {
jobIdFilterStr += ' OR ';
}
@@ -875,7 +876,7 @@ export function resultsServiceProvider(mlApiServices) {
})
.then((resp) => {
if (resp.hits.total !== 0) {
- _.each(resp.hits.hits, (hit) => {
+ each(resp.hits.hits, (hit) => {
obj.records.push(hit._source);
});
}
@@ -1000,7 +1001,7 @@ export function resultsServiceProvider(mlApiServices) {
})
.then((resp) => {
if (resp.hits.total !== 0) {
- _.each(resp.hits.hits, (hit) => {
+ each(resp.hits.hits, (hit) => {
obj.records.push(hit._source);
});
}
@@ -1079,8 +1080,8 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const dataByTimeBucket = _.get(resp, ['aggregations', 'eventRate', 'buckets'], []);
- _.each(dataByTimeBucket, (dataForTime) => {
+ const dataByTimeBucket = get(resp, ['aggregations', 'eventRate', 'buckets'], []);
+ each(dataByTimeBucket, (dataForTime) => {
const time = dataForTime.key;
obj.results[time] = dataForTime.doc_count;
});
@@ -1227,18 +1228,18 @@ export function resultsServiceProvider(mlApiServices) {
// Because of the sampling, results of metricFunctions which use sum or count
// can be significantly skewed. Taking into account totalHits we calculate a
// a factor to normalize results for these metricFunctions.
- const totalHits = _.get(resp, ['hits', 'total'], 0);
- const successfulShards = _.get(resp, ['_shards', 'successful'], 0);
+ const totalHits = get(resp, ['hits', 'total'], 0);
+ const successfulShards = get(resp, ['_shards', 'successful'], 0);
let normalizeFactor = 1;
if (totalHits > successfulShards * SAMPLER_TOP_TERMS_SHARD_SIZE) {
normalizeFactor = totalHits / (successfulShards * SAMPLER_TOP_TERMS_SHARD_SIZE);
}
- const dataByTime = _.get(resp, ['aggregations', 'sample', 'byTime', 'buckets'], []);
+ const dataByTime = get(resp, ['aggregations', 'sample', 'byTime', 'buckets'], []);
const data = dataByTime.reduce((d, dataForTime) => {
const date = +dataForTime.key;
- const entities = _.get(dataForTime, ['entities', 'buckets'], []);
+ const entities = get(dataForTime, ['entities', 'buckets'], []);
entities.forEach((entity) => {
let value = metricFunction === 'count' ? entity.doc_count : entity.metric.value;
@@ -1291,7 +1292,7 @@ export function resultsServiceProvider(mlApiServices) {
{ term: { job_id: jobId } },
];
- _.each(criteriaFields, (criteria) => {
+ each(criteriaFields, (criteria) => {
mustCriteria.push({
term: {
[criteria.fieldName]: criteria.fieldValue,
@@ -1339,11 +1340,11 @@ export function resultsServiceProvider(mlApiServices) {
},
})
.then((resp) => {
- const aggregationsByTime = _.get(resp, ['aggregations', 'times', 'buckets'], []);
- _.each(aggregationsByTime, (dataForTime) => {
+ const aggregationsByTime = get(resp, ['aggregations', 'times', 'buckets'], []);
+ each(aggregationsByTime, (dataForTime) => {
const time = dataForTime.key;
obj.results[time] = {
- score: _.get(dataForTime, ['recordScore', 'value']),
+ score: get(dataForTime, ['recordScore', 'value']),
};
});
diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js
index 86f12d7ca68c8..d825844ffa14b 100644
--- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js
+++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/forecasting_modal.js
@@ -9,7 +9,7 @@
*/
import PropTypes from 'prop-types';
-import _ from 'lodash';
+import get from 'lodash/get';
import React, { Component } from 'react';
@@ -250,8 +250,8 @@ export class ForecastingModalUI extends Component {
.getForecastRequestStats(this.props.job, forecastId)
.then((resp) => {
// Get the progress (stats value is between 0 and 1).
- const progress = _.get(resp, ['stats', 'forecast_progress'], previousProgress);
- const status = _.get(resp, ['stats', 'forecast_status']);
+ const progress = get(resp, ['stats', 'forecast_progress'], previousProgress);
+ const status = get(resp, ['stats', 'forecast_status']);
// The requests for forecast stats can get routed to different shards,
// and if these operate at different speeds there is a chance that a
@@ -263,7 +263,7 @@ export class ForecastingModalUI extends Component {
}
// Display any messages returned in the request stats.
- let messages = _.get(resp, ['stats', 'forecast_messages'], []);
+ let messages = get(resp, ['stats', 'forecast_messages'], []);
messages = messages.map((message) => ({ message, status: MESSAGE_LEVEL.WARNING }));
this.setState({ messages });
diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
index 190bce1639c4a..7ec59f4acbc51 100644
--- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
+++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
@@ -12,9 +12,13 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import useObservable from 'react-use/lib/useObservable';
-import _ from 'lodash';
+import isEqual from 'lodash/isEqual';
+import reduce from 'lodash/reduce';
+import each from 'lodash/each';
+import get from 'lodash/get';
import d3 from 'd3';
import moment from 'moment';
+import { i18n } from '@kbn/i18n';
import {
getSeverityWithLow,
@@ -49,8 +53,6 @@ import {
unhighlightFocusChartAnnotation,
} from './timeseries_chart_annotations';
-import { i18n } from '@kbn/i18n';
-
const focusZoomPanelHeight = 25;
const focusChartHeight = 310;
const focusHeight = focusZoomPanelHeight + focusChartHeight;
@@ -399,7 +401,7 @@ class TimeseriesChartIntl extends Component {
if (zoomFrom) {
focusLoadFrom = zoomFrom.getTime();
} else {
- focusLoadFrom = _.reduce(
+ focusLoadFrom = reduce(
combinedData,
(memo, point) => Math.min(memo, point.date.getTime()),
new Date(2099, 12, 31).getTime()
@@ -410,11 +412,7 @@ class TimeseriesChartIntl extends Component {
if (zoomTo) {
focusLoadTo = zoomTo.getTime();
} else {
- focusLoadTo = _.reduce(
- combinedData,
- (memo, point) => Math.max(memo, point.date.getTime()),
- 0
- );
+ focusLoadTo = reduce(combinedData, (memo, point) => Math.max(memo, point.date.getTime()), 0);
}
focusLoadTo = Math.min(focusLoadTo, contextXMax);
@@ -431,7 +429,7 @@ class TimeseriesChartIntl extends Component {
min: moment(new Date(contextXScaleDomain[0])),
max: moment(contextXScaleDomain[1]),
};
- if (!_.isEqual(newSelectedBounds, this.selectedBounds)) {
+ if (!isEqual(newSelectedBounds, this.selectedBounds)) {
this.selectedBounds = newSelectedBounds;
this.setContextBrushExtent(
new Date(contextXScaleDomain[0]),
@@ -764,7 +762,7 @@ class TimeseriesChartIntl extends Component {
})
.attr('class', (d) => {
let markerClass = 'metric-value';
- if (_.has(d, 'anomalyScore')) {
+ if (d.anomalyScore !== undefined) {
markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore).id}`;
}
return markerClass;
@@ -887,14 +885,14 @@ class TimeseriesChartIntl extends Component {
);
const zoomOptions = [{ durationMs: autoZoomDuration, label: 'auto' }];
- _.each(ZOOM_INTERVAL_OPTIONS, (option) => {
+ each(ZOOM_INTERVAL_OPTIONS, (option) => {
if (option.duration.asSeconds() > minSecs && option.duration.asSeconds() < boundsSecs) {
zoomOptions.push({ durationMs: option.duration.asMilliseconds(), label: option.label });
}
});
xPos += zoomLabel.node().getBBox().width + 4;
- _.each(zoomOptions, (option) => {
+ each(zoomOptions, (option) => {
const text = zoomGroup
.append('a')
.attr('data-ms', option.durationMs)
@@ -960,7 +958,7 @@ class TimeseriesChartIntl extends Component {
const combinedData =
contextForecastData === undefined ? data : data.concat(contextForecastData);
const valuesRange = { min: Number.MAX_VALUE, max: Number.MIN_VALUE };
- _.each(combinedData, (item) => {
+ each(combinedData, (item) => {
valuesRange.min = Math.min(item.value, valuesRange.min);
valuesRange.max = Math.max(item.value, valuesRange.max);
});
@@ -973,7 +971,7 @@ class TimeseriesChartIntl extends Component {
(contextForecastData !== undefined && contextForecastData.length > 0)
) {
const boundsRange = { min: Number.MAX_VALUE, max: Number.MIN_VALUE };
- _.each(combinedData, (item) => {
+ each(combinedData, (item) => {
boundsRange.min = Math.min(item.lower, boundsRange.min);
boundsRange.max = Math.max(item.upper, boundsRange.max);
});
@@ -1294,7 +1292,7 @@ class TimeseriesChartIntl extends Component {
if (swimlaneData !== undefined && swimlaneData.length > 0) {
// Adjust the earliest back to the time of the first swimlane point
// if this is before the time filter minimum.
- earliest = Math.min(_.first(swimlaneData).date.getTime(), bounds.min.valueOf());
+ earliest = Math.min(swimlaneData[0].date.getTime(), bounds.min.valueOf());
}
const contextAggMs = contextAggregationInterval.asMilliseconds();
@@ -1352,7 +1350,7 @@ class TimeseriesChartIntl extends Component {
const formattedDate = formatHumanReadableDateTimeSeconds(marker.date);
const tooltipData = [{ label: formattedDate }];
- if (_.has(marker, 'anomalyScore')) {
+ if (marker.anomalyScore !== undefined) {
const score = parseInt(marker.anomalyScore);
const displayScore = score > 0 ? score : '< 1';
tooltipData.push({
@@ -1387,7 +1385,7 @@ class TimeseriesChartIntl extends Component {
// Show actual/typical when available except for rare detectors.
// Rare detectors always have 1 as actual and the probability as typical.
// Exposing those values in the tooltip with actual/typical labels might irritate users.
- if (_.has(marker, 'actual') && marker.function !== 'rare') {
+ if (marker.actual !== undefined && marker.function !== 'rare') {
// Display the record actual in preference to the chart value, which may be
// different depending on the aggregation interval of the chart.
tooltipData.push({
@@ -1421,7 +1419,7 @@ class TimeseriesChartIntl extends Component {
},
valueAccessor: 'value',
});
- if (_.has(marker, 'byFieldName') && _.has(marker, 'numberOfCauses')) {
+ if (marker.byFieldName !== undefined && marker.numberOfCauses !== undefined) {
const numberOfCauses = marker.numberOfCauses;
// If numberOfCauses === 1, won't go into this block as actual/typical copied to top level fields.
const byFieldName = mlEscape(marker.byFieldName);
@@ -1488,7 +1486,7 @@ class TimeseriesChartIntl extends Component {
}
} else {
// TODO - need better formatting for small decimals.
- if (_.get(marker, 'isForecast', false) === true) {
+ if (get(marker, 'isForecast', false) === true) {
tooltipData.push({
label: i18n.translate(
'xpack.ml.timeSeriesExplorer.timeSeriesChart.withoutAnomalyScore.predictionLabel',
@@ -1548,7 +1546,7 @@ class TimeseriesChartIntl extends Component {
}
}
- if (_.has(marker, 'scheduledEvents')) {
+ if (marker.scheduledEvents !== undefined) {
marker.scheduledEvents.forEach((scheduledEvent, i) => {
tooltipData.push({
label: i18n.translate(
@@ -1569,7 +1567,7 @@ class TimeseriesChartIntl extends Component {
});
}
- if (_.has(marker, 'annotation')) {
+ if (marker.annotation !== undefined) {
tooltipData.length = 0;
// header
tooltipData.push({
diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts
index ce5a7565c519b..d1e959b33e5dc 100644
--- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts
+++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts
@@ -4,7 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import each from 'lodash/each';
+import find from 'lodash/find';
+import get from 'lodash/get';
+import filter from 'lodash/filter';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -35,8 +38,8 @@ function getMetricData(
// Extract the partition, by, over fields on which to filter.
const criteriaFields = [];
const detector = job.analysis_config.detectors[detectorIndex];
- if (_.has(detector, 'partition_field_name')) {
- const partitionEntity: any = _.find(entityFields, {
+ if (detector.partition_field_name !== undefined) {
+ const partitionEntity: any = find(entityFields, {
fieldName: detector.partition_field_name,
});
if (partitionEntity !== undefined) {
@@ -47,8 +50,8 @@ function getMetricData(
}
}
- if (_.has(detector, 'over_field_name')) {
- const overEntity: any = _.find(entityFields, { fieldName: detector.over_field_name });
+ if (detector.over_field_name !== undefined) {
+ const overEntity: any = find(entityFields, { fieldName: detector.over_field_name });
if (overEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'over_field_name', fieldValue: overEntity.fieldName },
@@ -57,8 +60,8 @@ function getMetricData(
}
}
- if (_.has(detector, 'by_field_name')) {
- const byEntity: any = _.find(entityFields, { fieldName: detector.by_field_name });
+ if (detector.by_field_name !== undefined) {
+ const byEntity: any = find(entityFields, { fieldName: detector.by_field_name });
if (byEntity !== undefined) {
criteriaFields.push(
{ fieldName: 'by_field_name', fieldValue: byEntity.fieldName },
@@ -97,7 +100,7 @@ function getMetricData(
)
.pipe(
map((resp) => {
- _.each(resp.results, (value, time) => {
+ each(resp.results, (value, time) => {
// @ts-ignore
obj.results[time] = {
actual: value,
@@ -134,7 +137,7 @@ function getChartDetails(
}
obj.results.functionLabel = functionLabel;
- const blankEntityFields = _.filter(entityFields, (entity) => {
+ const blankEntityFields = filter(entityFields, (entity) => {
return entity.fieldValue === null;
});
@@ -145,7 +148,7 @@ function getChartDetails(
obj.results.entityData.entities = entityFields;
resolve(obj);
} else {
- const entityFieldNames: string[] = _.map(blankEntityFields, 'fieldName');
+ const entityFieldNames: string[] = blankEntityFields.map((f) => f.fieldName);
ml.getCardinalityOfFields({
index: chartConfig.datafeedConfig.indices,
fieldNames: entityFieldNames,
@@ -155,12 +158,12 @@ function getChartDetails(
latestMs,
})
.then((results: any) => {
- _.each(blankEntityFields, (field) => {
+ each(blankEntityFields, (field) => {
// results will not contain keys for non-aggregatable fields,
// so store as 0 to indicate over all field values.
obj.results.entityData.entities.push({
fieldName: field.fieldName,
- cardinality: _.get(results, field.fieldName, 0),
+ cardinality: get(results, field.fieldName, 0),
});
});
diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/timeseriesexplorer_utils.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/timeseriesexplorer_utils.js
index 857db302e664e..7d14bb43ef811 100644
--- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/timeseriesexplorer_utils.js
+++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/timeseriesexplorer_utils.js
@@ -10,7 +10,9 @@
* Viewer dashboard.
*/
-import _ from 'lodash';
+import each from 'lodash/each';
+import get from 'lodash/get';
+import find from 'lodash/find';
import moment from 'moment-timezone';
import { isTimeSeriesViewJob } from '../../../../common/util/job_utils';
@@ -41,7 +43,7 @@ export function createTimeSeriesJobData(jobs) {
export function processMetricPlotResults(metricPlotData, modelPlotEnabled) {
const metricPlotChartData = [];
if (modelPlotEnabled === true) {
- _.each(metricPlotData, (dataForTime, time) => {
+ each(metricPlotData, (dataForTime, time) => {
metricPlotChartData.push({
date: new Date(+time),
lower: dataForTime.modelLower,
@@ -50,7 +52,7 @@ export function processMetricPlotResults(metricPlotData, modelPlotEnabled) {
});
});
} else {
- _.each(metricPlotData, (dataForTime, time) => {
+ each(metricPlotData, (dataForTime, time) => {
metricPlotChartData.push({
date: new Date(+time),
value: dataForTime.actual,
@@ -66,7 +68,7 @@ export function processMetricPlotResults(metricPlotData, modelPlotEnabled) {
// value, lower and upper keys.
export function processForecastResults(forecastData) {
const forecastPlotChartData = [];
- _.each(forecastData, (dataForTime, time) => {
+ each(forecastData, (dataForTime, time) => {
forecastPlotChartData.push({
date: new Date(+time),
isForecast: true,
@@ -83,7 +85,7 @@ export function processForecastResults(forecastData) {
// i.e. array of Objects with keys date (JavaScript date) and score.
export function processRecordScoreResults(scoreData) {
const bucketScoreData = [];
- _.each(scoreData, (dataForTime, time) => {
+ each(scoreData, (dataForTime, time) => {
bucketScoreData.push({
date: new Date(+time),
score: dataForTime.score,
@@ -153,7 +155,7 @@ export function processDataForFocusAnomalies(
chartPoint.anomalyScore = recordScore;
chartPoint.function = record.function;
- if (_.has(record, 'actual')) {
+ if (record.actual !== undefined) {
// If cannot match chart point for anomaly time
// substitute the value with the record's actual so it won't plot as null/0
if (chartPoint.value === null) {
@@ -163,13 +165,13 @@ export function processDataForFocusAnomalies(
chartPoint.actual = record.actual;
chartPoint.typical = record.typical;
} else {
- const causes = _.get(record, 'causes', []);
+ const causes = get(record, 'causes', []);
if (causes.length > 0) {
chartPoint.byFieldName = record.by_field_name;
chartPoint.numberOfCauses = causes.length;
if (causes.length === 1) {
// If only a single cause, copy actual and typical values to the top level.
- const cause = _.first(record.causes);
+ const cause = record.causes[0];
chartPoint.actual = cause.actual;
chartPoint.typical = cause.typical;
// substitute the value with the record's actual so it won't plot as null/0
@@ -180,7 +182,7 @@ export function processDataForFocusAnomalies(
}
}
- if (_.has(record, 'multi_bucket_impact')) {
+ if (record.multi_bucket_impact !== undefined) {
chartPoint.multiBucketImpact = record.multi_bucket_impact;
}
}
@@ -194,7 +196,7 @@ export function processDataForFocusAnomalies(
// which correspond to times of scheduled events for the job.
export function processScheduledEventsForChart(chartData, scheduledEvents) {
if (scheduledEvents !== undefined) {
- _.each(scheduledEvents, (events, time) => {
+ each(scheduledEvents, (events, time) => {
const chartPoint = findNearestChartPointToTime(chartData, time);
if (chartPoint !== undefined) {
// Note if the scheduled event coincides with an absence of the underlying metric data,
@@ -301,7 +303,7 @@ export function calculateAggregationInterval(bounds, bucketsTarget, jobs, select
// Ensure the aggregation interval is always a multiple of the bucket span to avoid strange
// behaviour such as adjacent chart buckets holding different numbers of job results.
- const bucketSpanSeconds = _.find(jobs, { id: selectedJob.job_id }).bucketSpanSeconds;
+ const bucketSpanSeconds = find(jobs, { id: selectedJob.job_id }).bucketSpanSeconds;
let aggInterval = buckets.getIntervalToNearestMultiple(bucketSpanSeconds);
// Set the interval back to the job bucket span if the auto interval is smaller.
@@ -324,8 +326,8 @@ export function calculateDefaultFocusRange(
const combinedData =
isForecastData === false ? contextChartData : contextChartData.concat(contextForecastData);
- const earliestDataDate = _.first(combinedData).date;
- const latestDataDate = _.last(combinedData).date;
+ const earliestDataDate = combinedData[0].date;
+ const latestDataDate = combinedData[combinedData.length - 1].date;
let rangeEarliestMs;
let rangeLatestMs;
@@ -333,8 +335,8 @@ export function calculateDefaultFocusRange(
if (isForecastData === true) {
// Return a range centred on the start of the forecast range, depending
// on the time range of the forecast and data.
- const earliestForecastDataDate = _.first(contextForecastData).date;
- const latestForecastDataDate = _.last(contextForecastData).date;
+ const earliestForecastDataDate = contextForecastData[0].date;
+ const latestForecastDataDate = contextForecastData[contextForecastData.length - 1].date;
rangeLatestMs = Math.min(
earliestForecastDataDate.getTime() + autoZoomDuration / 2,
@@ -379,7 +381,7 @@ export function getAutoZoomDuration(jobs, selectedJob) {
// Calculate the 'auto' zoom duration which shows data at bucket span granularity.
// Get the minimum bucket span of selected jobs.
// TODO - only look at jobs for which data has been returned?
- const bucketSpanSeconds = _.find(jobs, { id: selectedJob.job_id }).bucketSpanSeconds;
+ const bucketSpanSeconds = find(jobs, { id: selectedJob.job_id }).bucketSpanSeconds;
// In most cases the duration can be obtained by simply multiplying the points target
// Check that this duration returns the bucket span when run back through the
diff --git a/x-pack/plugins/ml/public/application/util/chart_config_builder.js b/x-pack/plugins/ml/public/application/util/chart_config_builder.js
index 3b09e09d3dd4a..bc63404a106db 100644
--- a/x-pack/plugins/ml/public/application/util/chart_config_builder.js
+++ b/x-pack/plugins/ml/public/application/util/chart_config_builder.js
@@ -9,7 +9,7 @@
* in the source metric data.
*/
-import _ from 'lodash';
+import get from 'lodash/get';
import { mlFunctionToESAggregation } from '../../../common/util/job_utils';
@@ -44,15 +44,16 @@ export function buildConfigFromDetector(job, detectorIndex) {
// aggregations//aggregations//cardinality/field
// or aggs//aggs//cardinality/field
let cardinalityField = undefined;
- const topAgg = _.get(job.datafeed_config, 'aggregations') || _.get(job.datafeed_config, 'aggs');
- if (topAgg !== undefined && _.values(topAgg).length > 0) {
+ const topAgg = get(job.datafeed_config, 'aggregations') || get(job.datafeed_config, 'aggs');
+ if (topAgg !== undefined && Object.values(topAgg).length > 0) {
cardinalityField =
- _.get(_.values(topAgg)[0], [
+ get(Object.values(topAgg)[0], [
'aggregations',
summaryCountFieldName,
'cardinality',
'field',
- ]) || _.get(_.values(topAgg)[0], ['aggs', summaryCountFieldName, 'cardinality', 'field']);
+ ]) ||
+ get(Object.values(topAgg)[0], ['aggs', summaryCountFieldName, 'cardinality', 'field']);
}
if (detector.function === 'non_zero_count' && cardinalityField !== undefined) {
diff --git a/x-pack/plugins/ml/public/application/util/inherits.js b/x-pack/plugins/ml/public/application/util/inherits.js
deleted file mode 100644
index bf16e573117d9..0000000000000
--- a/x-pack/plugins/ml/public/application/util/inherits.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-// create a property descriptor for properties
-// that won't change
-function describeConst(val) {
- return {
- writable: false,
- enumerable: false,
- configurable: false,
- value: val,
- };
-}
-
-/**
- * Apply inheritance in the legacy `_.class(SubClass).inherits(SuperClass)`
- * @param {Function} SubClass class that should inherit SuperClass
- * @param {Function} SuperClass
- * @return {Function}
- */
-export function inherits(SubClass, SuperClass) {
- const prototype = Object.create(SuperClass.prototype, {
- constructor: describeConst(SubClass),
- superConstructor: describeConst(SuperClass),
- });
-
- Object.defineProperties(SubClass, {
- prototype: describeConst(prototype),
- Super: describeConst(SuperClass),
- });
-
- return SubClass;
-}
diff --git a/x-pack/plugins/ml/public/application/util/time_buckets.js b/x-pack/plugins/ml/public/application/util/time_buckets.js
index 19d499faf6c8d..15b8f24804ec8 100644
--- a/x-pack/plugins/ml/public/application/util/time_buckets.js
+++ b/x-pack/plugins/ml/public/application/util/time_buckets.js
@@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import isPlainObject from 'lodash/isPlainObject';
+import isString from 'lodash/isString';
+import ary from 'lodash/ary';
+import sortBy from 'lodash/sortBy';
+import assign from 'lodash/assign';
import moment from 'moment';
import dateMath from '@elastic/datemath';
@@ -80,16 +84,16 @@ TimeBuckets.prototype.setBounds = function (input) {
if (!input) return this.clearBounds();
let bounds;
- if (_.isPlainObject(input)) {
+ if (isPlainObject(input)) {
// accept the response from timefilter.getActiveBounds()
bounds = [input.min, input.max];
} else {
bounds = Array.isArray(input) ? input : [];
}
- const moments = _(bounds).map(_.ary(moment, 1)).sortBy(Number);
+ const moments = sortBy(bounds.map(ary(moment, 1)), Number);
- const valid = moments.size() === 2 && moments.every(isValidMoment);
+ const valid = moments.length === 2 && moments.every(isValidMoment);
if (!valid) {
this.clearBounds();
throw new Error('invalid bounds set: ' + input);
@@ -175,7 +179,7 @@ TimeBuckets.prototype.setInterval = function (input) {
return;
}
- if (_.isString(interval)) {
+ if (isString(interval)) {
input = interval;
interval = parseInterval(interval);
if (+interval === 0) {
@@ -256,7 +260,7 @@ TimeBuckets.prototype.getInterval = function () {
if (+scaled === +interval) return interval;
decorateInterval(interval, duration);
- return _.assign(scaled, {
+ return assign(scaled, {
preScaled: interval,
scale: interval / scaled,
scaled: true,
@@ -287,7 +291,7 @@ TimeBuckets.prototype.getIntervalToNearestMultiple = function (divisorSecs) {
decorateInterval(nearestMultipleInt, this.getDuration());
// Check to see if the new interval is scaled compared to the original.
- const preScaled = _.get(interval, 'preScaled');
+ const preScaled = interval.preScaled;
if (preScaled !== undefined && preScaled < nearestMultipleInt) {
nearestMultipleInt.preScaled = preScaled;
nearestMultipleInt.scale = preScaled / nearestMultipleInt;
diff --git a/x-pack/plugins/ml/server/lib/telemetry/telemetry.ts b/x-pack/plugins/ml/server/lib/telemetry/telemetry.ts
index f2162ff2c3d30..d9ebccd554733 100644
--- a/x-pack/plugins/ml/server/lib/telemetry/telemetry.ts
+++ b/x-pack/plugins/ml/server/lib/telemetry/telemetry.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import isEmpty from 'lodash/isEmpty';
import { ISavedObjectsRepository } from 'kibana/server';
import { getInternalRepository } from './internal_repository';
@@ -58,7 +58,7 @@ export async function updateTelemetry(internalRepo?: ISavedObjectsRepository) {
let telemetry = await getTelemetry(internalRepository);
// Create if doesn't exist
- if (telemetry === null || _.isEmpty(telemetry)) {
+ if (telemetry === null || isEmpty(telemetry)) {
const newTelemetrySavedObject = await internalRepository.create(
TELEMETRY_DOC_ID,
initTelemetry(),
diff --git a/x-pack/plugins/ml/server/models/annotation_service/annotation.ts b/x-pack/plugins/ml/server/models/annotation_service/annotation.ts
index 8094689abf3e5..a585449db0a25 100644
--- a/x-pack/plugins/ml/server/models/annotation_service/annotation.ts
+++ b/x-pack/plugins/ml/server/models/annotation_service/annotation.ts
@@ -5,7 +5,8 @@
*/
import Boom from 'boom';
-import _ from 'lodash';
+import each from 'lodash/each';
+import get from 'lodash/get';
import { ILegacyScopedClusterClient } from 'kibana/server';
import { ANNOTATION_EVENT_USER, ANNOTATION_TYPE } from '../../../common/constants/annotations';
@@ -190,7 +191,7 @@ export function annotationProvider({ callAsInternalUser }: ILegacyScopedClusterC
if (jobIds && jobIds.length > 0 && !(jobIds.length === 1 && jobIds[0] === '*')) {
let jobIdFilterStr = '';
- _.each(jobIds, (jobId, i: number) => {
+ each(jobIds, (jobId, i: number) => {
jobIdFilterStr += `${i! > 0 ? ' OR ' : ''}job_id:${jobId}`;
});
boolCriteria.push({
@@ -293,7 +294,7 @@ export function annotationProvider({ callAsInternalUser }: ILegacyScopedClusterC
throw new Error(`Annotations couldn't be retrieved from Elasticsearch.`);
}
- const docs: Annotations = _.get(resp, ['hits', 'hits'], []).map((d: EsResult) => {
+ const docs: Annotations = get(resp, ['hits', 'hits'], []).map((d: EsResult) => {
// get the original source document and the document id, we need it
// to identify the annotation when editing/deleting it.
// if original `event` is undefined then substitute with 'user` by default
@@ -305,7 +306,7 @@ export function annotationProvider({ callAsInternalUser }: ILegacyScopedClusterC
} as Annotation;
});
- const aggregations = _.get(resp, ['aggregations'], {}) as EsAggregationResult;
+ const aggregations = get(resp, ['aggregations'], {}) as EsAggregationResult;
if (fields) {
obj.aggregations = aggregations;
}
diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js
index 3758547779403..381c615051e3b 100644
--- a/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js
+++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/bucket_span_estimator.js
@@ -4,7 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
+import each from 'lodash/each';
+import remove from 'lodash/remove';
+import sortBy from 'lodash/sortBy';
+import get from 'lodash/get';
import { mlLog } from '../../client/log';
@@ -91,7 +95,7 @@ export function estimateBucketSpanFactory(mlClusterClient) {
} else {
// loop over partition values
for (let j = 0; j < this.splitFieldValues.length; j++) {
- const queryCopy = _.cloneDeep(this.query);
+ const queryCopy = cloneDeep(this.query);
// add a term to the query to filter on the partition value
queryCopy.bool.must.push({
term: {
@@ -151,7 +155,7 @@ export function estimateBucketSpanFactory(mlClusterClient) {
}
};
- _.each(this.checkers, (check) => {
+ each(this.checkers, (check) => {
check.check
.run()
.then((interval) => {
@@ -174,7 +178,7 @@ export function estimateBucketSpanFactory(mlClusterClient) {
}
processResults() {
- const allResults = _.map(this.checkers, 'result');
+ const allResults = this.checkers.map((c) => c.result);
let reducedResults = [];
const numberOfSplitFields = this.splitFieldValues.length || 1;
@@ -185,8 +189,8 @@ export function estimateBucketSpanFactory(mlClusterClient) {
const pos = i * numberOfSplitFields;
let resultsSubset = allResults.slice(pos, pos + numberOfSplitFields);
// remove results of tests which have failed
- resultsSubset = _.remove(resultsSubset, (res) => res !== null);
- resultsSubset = _.sortBy(resultsSubset, (r) => r.ms);
+ resultsSubset = remove(resultsSubset, (res) => res !== null);
+ resultsSubset = sortBy(resultsSubset, (r) => r.ms);
const tempMedian = this.findMedian(resultsSubset);
if (tempMedian !== null) {
@@ -194,7 +198,7 @@ export function estimateBucketSpanFactory(mlClusterClient) {
}
}
- reducedResults = _.sortBy(reducedResults, (r) => r.ms);
+ reducedResults = sortBy(reducedResults, (r) => r.ms);
return this.findMedian(reducedResults);
}
@@ -256,7 +260,7 @@ export function estimateBucketSpanFactory(mlClusterClient) {
},
})
.then((resp) => {
- const value = _.get(resp, ['aggregations', 'field_count', 'value'], 0);
+ const value = get(resp, ['aggregations', 'field_count', 'value'], 0);
resolve(value);
})
.catch((resp) => {
@@ -293,9 +297,10 @@ export function estimateBucketSpanFactory(mlClusterClient) {
},
})
.then((partitionResp) => {
- if (_.has(partitionResp, 'aggregations.fields_bucket_counts.buckets')) {
+ // eslint-disable-next-line camelcase
+ if (partitionResp.aggregations?.fields_bucket_counts?.buckets !== undefined) {
const buckets = partitionResp.aggregations.fields_bucket_counts.buckets;
- fieldValues = _.map(buckets, (b) => b.key);
+ fieldValues = buckets.map((b) => b.key);
}
resolve(fieldValues);
})
diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js
index 347843e276c36..d3bbd59f3cf9b 100644
--- a/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js
+++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js
@@ -10,7 +10,7 @@
* And a minimum bucket span
*/
-import _ from 'lodash';
+import get from 'lodash/get';
export function polledDataCheckerFactory({ callAsCurrentUser }) {
class PolledDataChecker {
@@ -29,7 +29,7 @@ export function polledDataCheckerFactory({ callAsCurrentUser }) {
const interval = { name: '1m', ms: 60000 };
this.performSearch(interval.ms)
.then((resp) => {
- const fullBuckets = _.get(resp, 'aggregations.non_empty_buckets.buckets', []);
+ const fullBuckets = get(resp, 'aggregations.non_empty_buckets.buckets', []);
const result = this.isPolledData(fullBuckets, interval);
if (result.pass) {
// data is polled, return a flag and the minimumBucketSpan which should be
diff --git a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts
index 7f19f32373e07..838315d8d272c 100644
--- a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts
+++ b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts
@@ -5,7 +5,10 @@
*/
import { ILegacyScopedClusterClient } from 'kibana/server';
-import _ from 'lodash';
+import get from 'lodash/get';
+import each from 'lodash/each';
+import last from 'lodash/last';
+import find from 'lodash/find';
import { KBN_FIELD_TYPES } from '../../../../../../src/plugins/data/server';
import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types';
import { getSafeAggregationName } from '../../../common/util/job_utils';
@@ -216,7 +219,7 @@ const getAggIntervals = async (
const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize);
const aggregations =
- aggsPath.length > 0 ? _.get(respStats.aggregations, aggsPath) : respStats.aggregations;
+ aggsPath.length > 0 ? get(respStats.aggregations, aggsPath) : respStats.aggregations;
return Object.keys(aggregations).reduce((p, aggName) => {
const stats = [aggregations[aggName].min, aggregations[aggName].max];
@@ -300,9 +303,7 @@ export const getHistogramsForFields = async (
const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize);
const aggregations =
- aggsPath.length > 0
- ? _.get(respChartsData.aggregations, aggsPath)
- : respChartsData.aggregations;
+ aggsPath.length > 0 ? get(respChartsData.aggregations, aggsPath) : respChartsData.aggregations;
const chartsData: ChartData[] = fields.map(
(field): ChartData => {
@@ -382,8 +383,8 @@ export class DataVisualizer {
// To avoid checking for the existence of too many aggregatable fields in one request,
// split the check into multiple batches (max 200 fields per request).
const batches: string[][] = [[]];
- _.each(aggregatableFields, (field) => {
- let lastArray: string[] = _.last(batches) as string[];
+ each(aggregatableFields, (field) => {
+ let lastArray: string[] = last(batches) as string[];
if (lastArray.length === AGGREGATABLE_EXISTS_REQUEST_BATCH_SIZE) {
lastArray = [];
batches.push(lastArray);
@@ -475,7 +476,7 @@ export class DataVisualizer {
// Batch up fields by type, getting stats for multiple fields at a time.
const batches: Field[][] = [];
const batchedFields: { [key: string]: Field[][] } = {};
- _.each(fields, (field) => {
+ each(fields, (field) => {
if (field.fieldName === undefined) {
// undefined fieldName is used for a document count request.
// getDocumentCountStats requires timeField - don't add to batched requests if not defined
@@ -487,7 +488,7 @@ export class DataVisualizer {
if (batchedFields[fieldType] === undefined) {
batchedFields[fieldType] = [[]];
}
- let lastArray: Field[] = _.last(batchedFields[fieldType]) as Field[];
+ let lastArray: Field[] = last(batchedFields[fieldType]) as Field[];
if (lastArray.length === FIELDS_REQUEST_BATCH_SIZE) {
lastArray = [];
batchedFields[fieldType].push(lastArray);
@@ -496,7 +497,7 @@ export class DataVisualizer {
}
});
- _.each(batchedFields, (lists) => {
+ each(batchedFields, (lists) => {
batches.push(...lists);
});
@@ -636,7 +637,7 @@ export class DataVisualizer {
body,
});
const aggregations = resp.aggregations;
- const totalCount = _.get(resp, ['hits', 'total'], 0);
+ const totalCount = get(resp, ['hits', 'total'], 0);
const stats = {
totalCount,
aggregatableExistsFields: [] as FieldData[],
@@ -645,12 +646,12 @@ export class DataVisualizer {
const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize);
const sampleCount =
- samplerShardSize > 0 ? _.get(aggregations, ['sample', 'doc_count'], 0) : totalCount;
+ samplerShardSize > 0 ? get(aggregations, ['sample', 'doc_count'], 0) : totalCount;
aggregatableFields.forEach((field, i) => {
const safeFieldName = getSafeAggregationName(field, i);
- const count = _.get(aggregations, [...aggsPath, `${safeFieldName}_count`, 'doc_count'], 0);
+ const count = get(aggregations, [...aggsPath, `${safeFieldName}_count`, 'doc_count'], 0);
if (count > 0) {
- const cardinality = _.get(
+ const cardinality = get(
aggregations,
[...aggsPath, `${safeFieldName}_cardinality`, 'value'],
0
@@ -745,12 +746,12 @@ export class DataVisualizer {
});
const buckets: { [key: string]: number } = {};
- const dataByTimeBucket: Array<{ key: string; doc_count: number }> = _.get(
+ const dataByTimeBucket: Array<{ key: string; doc_count: number }> = get(
resp,
['aggregations', 'eventRate', 'buckets'],
[]
);
- _.each(dataByTimeBucket, (dataForTime) => {
+ each(dataByTimeBucket, (dataForTime) => {
const time = dataForTime.key;
buckets[time] = dataForTime.doc_count;
});
@@ -851,12 +852,12 @@ export class DataVisualizer {
const batchStats: NumericFieldStats[] = [];
fields.forEach((field, i) => {
const safeFieldName = getSafeAggregationName(field.fieldName, i);
- const docCount = _.get(
+ const docCount = get(
aggregations,
[...aggsPath, `${safeFieldName}_field_stats`, 'doc_count'],
0
);
- const fieldStatsResp = _.get(
+ const fieldStatsResp = get(
aggregations,
[...aggsPath, `${safeFieldName}_field_stats`, 'actual_stats'],
{}
@@ -867,20 +868,20 @@ export class DataVisualizer {
topAggsPath.push('top');
}
- const topValues: Bucket[] = _.get(aggregations, [...topAggsPath, 'buckets'], []);
+ const topValues: Bucket[] = get(aggregations, [...topAggsPath, 'buckets'], []);
const stats: NumericFieldStats = {
fieldName: field.fieldName,
count: docCount,
- min: _.get(fieldStatsResp, 'min', 0),
- max: _.get(fieldStatsResp, 'max', 0),
- avg: _.get(fieldStatsResp, 'avg', 0),
+ min: get(fieldStatsResp, 'min', 0),
+ max: get(fieldStatsResp, 'max', 0),
+ avg: get(fieldStatsResp, 'avg', 0),
isTopValuesSampled:
field.cardinality >= SAMPLER_TOP_TERMS_THRESHOLD || samplerShardSize > 0,
topValues,
topValuesSampleSize: topValues.reduce(
(acc, curr) => acc + curr.doc_count,
- _.get(aggregations, [...topAggsPath, 'sum_other_doc_count'], 0)
+ get(aggregations, [...topAggsPath, 'sum_other_doc_count'], 0)
),
topValuesSamplerShardSize:
field.cardinality >= SAMPLER_TOP_TERMS_THRESHOLD
@@ -889,12 +890,12 @@ export class DataVisualizer {
};
if (stats.count > 0) {
- const percentiles = _.get(
+ const percentiles = get(
aggregations,
[...aggsPath, `${safeFieldName}_percentiles`, 'values'],
[]
);
- const medianPercentile: { value: number; key: number } | undefined = _.find(percentiles, {
+ const medianPercentile: { value: number; key: number } | undefined = find(percentiles, {
key: 50,
});
stats.median = medianPercentile !== undefined ? medianPercentile!.value : 0;
@@ -978,7 +979,7 @@ export class DataVisualizer {
topAggsPath.push('top');
}
- const topValues: Bucket[] = _.get(aggregations, [...topAggsPath, 'buckets'], []);
+ const topValues: Bucket[] = get(aggregations, [...topAggsPath, 'buckets'], []);
const stats = {
fieldName: field.fieldName,
@@ -987,7 +988,7 @@ export class DataVisualizer {
topValues,
topValuesSampleSize: topValues.reduce(
(acc, curr) => acc + curr.doc_count,
- _.get(aggregations, [...topAggsPath, 'sum_other_doc_count'], 0)
+ get(aggregations, [...topAggsPath, 'sum_other_doc_count'], 0)
),
topValuesSamplerShardSize:
field.cardinality >= SAMPLER_TOP_TERMS_THRESHOLD
@@ -1046,12 +1047,12 @@ export class DataVisualizer {
const batchStats: DateFieldStats[] = [];
fields.forEach((field, i) => {
const safeFieldName = getSafeAggregationName(field.fieldName, i);
- const docCount = _.get(
+ const docCount = get(
aggregations,
[...aggsPath, `${safeFieldName}_field_stats`, 'doc_count'],
0
);
- const fieldStatsResp = _.get(
+ const fieldStatsResp = get(
aggregations,
[...aggsPath, `${safeFieldName}_field_stats`, 'actual_stats'],
{}
@@ -1059,8 +1060,8 @@ export class DataVisualizer {
batchStats.push({
fieldName: field.fieldName,
count: docCount,
- earliest: _.get(fieldStatsResp, 'min', 0),
- latest: _.get(fieldStatsResp, 'max', 0),
+ earliest: get(fieldStatsResp, 'min', 0),
+ latest: get(fieldStatsResp, 'max', 0),
});
});
@@ -1115,17 +1116,17 @@ export class DataVisualizer {
const safeFieldName = getSafeAggregationName(field.fieldName, i);
const stats: BooleanFieldStats = {
fieldName: field.fieldName,
- count: _.get(aggregations, [...aggsPath, `${safeFieldName}_value_count`, 'doc_count'], 0),
+ count: get(aggregations, [...aggsPath, `${safeFieldName}_value_count`, 'doc_count'], 0),
trueCount: 0,
falseCount: 0,
};
- const valueBuckets: Array<{ [key: string]: number }> = _.get(
+ const valueBuckets: Array<{ [key: string]: number }> = get(
aggregations,
[...aggsPath, `${safeFieldName}_values`, 'buckets'],
[]
);
- _.forEach(valueBuckets, (bucket) => {
+ valueBuckets.forEach((bucket) => {
stats[`${bucket.key_as_string}Count`] = bucket.doc_count;
});
@@ -1182,8 +1183,8 @@ export class DataVisualizer {
// If the field is not in the _source (as will happen if the
// field is populated using copy_to in the index mapping),
// there will be no example to add.
- // Use lodash _.get() to support field names containing dots.
- const example: any = _.get(hits[i]._source, field);
+ // Use lodash get() to support field names containing dots.
+ const example: any = get(hits[i]._source, field);
if (example !== undefined && stats.examples.indexOf(example) === -1) {
stats.examples.push(example);
if (stats.examples.length === maxExamples) {
@@ -1216,7 +1217,7 @@ export class DataVisualizer {
// Look ahead to the last percentiles and process these too if
// they don't add more than 50% to the value range.
- const lastValue = (_.last(percentileBuckets) as any).value;
+ const lastValue = (last(percentileBuckets) as any).value;
const upperBound = lowerBound + 1.5 * (lastValue - lowerBound);
const filteredLength = percentileBuckets.length;
for (let i = filteredLength; i < percentiles.length; i++) {
@@ -1237,7 +1238,7 @@ export class DataVisualizer {
// Add in 0-5 and 95-100% if they don't add more
// than 25% to the value range at either end.
- const lastValue: number = (_.last(percentileBuckets) as any).value;
+ const lastValue: number = (last(percentileBuckets) as any).value;
const maxDiff = 0.25 * (lastValue - lowerBound);
if (lowerBound - dataMin < maxDiff) {
percentileBuckets.splice(0, 0, percentiles[0]);
diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_cardinality.test.ts b/x-pack/plugins/ml/server/models/job_validation/validate_cardinality.test.ts
index 92933877e2836..16ee70ad9efde 100644
--- a/x-pack/plugins/ml/server/models/job_validation/validate_cardinality.test.ts
+++ b/x-pack/plugins/ml/server/models/job_validation/validate_cardinality.test.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
import { ILegacyScopedClusterClient } from 'kibana/server';
@@ -145,7 +145,7 @@ describe('ML - validateCardinality', () => {
test: (ids: string[]) => void
) => {
const job = getJobConfig(fieldName);
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(
mlClusterClientFactory(mockCardinality),
@@ -250,7 +250,7 @@ describe('ML - validateCardinality', () => {
it(`disabled model_plot, over field cardinality of ${cardinality} doesn't trigger a warning`, () => {
const job = (getJobConfig('over_field_name') as unknown) as CombinedJob;
job.model_plot_config = { enabled: false };
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(mlClusterClientFactory(mockCardinality), job).then((messages) => {
const ids = messages.map((m) => m.id);
@@ -261,7 +261,7 @@ describe('ML - validateCardinality', () => {
it(`enabled model_plot, over field cardinality of ${cardinality} triggers a model plot warning`, () => {
const job = (getJobConfig('over_field_name') as unknown) as CombinedJob;
job.model_plot_config = { enabled: true };
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(mlClusterClientFactory(mockCardinality), job).then((messages) => {
const ids = messages.map((m) => m.id);
@@ -272,7 +272,7 @@ describe('ML - validateCardinality', () => {
it(`disabled model_plot, by field cardinality of ${cardinality} triggers a field cardinality warning`, () => {
const job = (getJobConfig('by_field_name') as unknown) as CombinedJob;
job.model_plot_config = { enabled: false };
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(mlClusterClientFactory(mockCardinality), job).then((messages) => {
const ids = messages.map((m) => m.id);
@@ -283,7 +283,7 @@ describe('ML - validateCardinality', () => {
it(`enabled model_plot, by field cardinality of ${cardinality} triggers a model plot warning and field cardinality warning`, () => {
const job = (getJobConfig('by_field_name') as unknown) as CombinedJob;
job.model_plot_config = { enabled: true };
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(mlClusterClientFactory(mockCardinality), job).then((messages) => {
const ids = messages.map((m) => m.id);
@@ -294,7 +294,7 @@ describe('ML - validateCardinality', () => {
it(`enabled model_plot with terms, by field cardinality of ${cardinality} triggers just field cardinality warning`, () => {
const job = (getJobConfig('by_field_name') as unknown) as CombinedJob;
job.model_plot_config = { enabled: true, terms: 'AAL,AAB' };
- const mockCardinality = _.cloneDeep(mockResponses);
+ const mockCardinality = cloneDeep(mockResponses);
mockCardinality.search.aggregations.airline_cardinality.value = cardinality;
return validateCardinality(mlClusterClientFactory(mockCardinality), job).then((messages) => {
const ids = messages.map((m) => m.id);
diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_time_range.test.ts b/x-pack/plugins/ml/server/models/job_validation/validate_time_range.test.ts
index f74d8a26ef370..a45be189ba3d8 100644
--- a/x-pack/plugins/ml/server/models/job_validation/validate_time_range.test.ts
+++ b/x-pack/plugins/ml/server/models/job_validation/validate_time_range.test.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import cloneDeep from 'lodash/cloneDeep';
import { ILegacyScopedClusterClient } from 'kibana/server';
@@ -144,7 +144,7 @@ describe('ML - validateTimeRange', () => {
});
it('invalid time field', () => {
- const mockSearchResponseInvalid = _.cloneDeep(mockSearchResponse);
+ const mockSearchResponseInvalid = cloneDeep(mockSearchResponse);
mockSearchResponseInvalid.fieldCaps = undefined;
const duration = { start: 0, end: 1 };
return validateTimeRange(
diff --git a/x-pack/plugins/ml/server/models/results_service/build_anomaly_table_items.js b/x-pack/plugins/ml/server/models/results_service/build_anomaly_table_items.js
index e664a1403d7d6..588e0e10a8d63 100644
--- a/x-pack/plugins/ml/server/models/results_service/build_anomaly_table_items.js
+++ b/x-pack/plugins/ml/server/models/results_service/build_anomaly_table_items.js
@@ -4,7 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import sortBy from 'lodash/sortBy';
+import each from 'lodash/each';
import moment from 'moment-timezone';
import {
@@ -55,7 +56,7 @@ export function buildAnomalyTableItems(anomalyRecords, aggregationInterval, date
if (source.influencers !== undefined) {
const influencers = [];
- const sourceInfluencers = _.sortBy(source.influencers, 'influencer_field_name');
+ const sourceInfluencers = sortBy(source.influencers, 'influencer_field_name');
sourceInfluencers.forEach((influencer) => {
const influencerFieldName = influencer.influencer_field_name;
influencer.influencer_field_values.forEach((influencerFieldValue) => {
@@ -172,10 +173,10 @@ function aggregateAnomalies(anomalyRecords, interval, dateFormatTz) {
// Flatten the aggregatedData to give a list of records with
// the highest score per bucketed time / jobId / detectorIndex.
const summaryRecords = [];
- _.each(aggregatedData, (times, roundedTime) => {
- _.each(times, (jobIds) => {
- _.each(jobIds, (entityDetectors) => {
- _.each(entityDetectors, (record) => {
+ each(aggregatedData, (times, roundedTime) => {
+ each(times, (jobIds) => {
+ each(jobIds, (entityDetectors) => {
+ each(entityDetectors, (record) => {
summaryRecords.push({
time: +roundedTime,
source: record,
diff --git a/x-pack/plugins/ml/server/models/results_service/results_service.ts b/x-pack/plugins/ml/server/models/results_service/results_service.ts
index 04997e517bba9..8e71384942b57 100644
--- a/x-pack/plugins/ml/server/models/results_service/results_service.ts
+++ b/x-pack/plugins/ml/server/models/results_service/results_service.ts
@@ -4,7 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
+import sortBy from 'lodash/sortBy';
+import slice from 'lodash/slice';
+import get from 'lodash/get';
import moment from 'moment';
import { SearchResponse } from 'elasticsearch';
import { ILegacyScopedClusterClient } from 'kibana/server';
@@ -175,7 +177,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
});
// Sort anomalies in ascending time order.
- records = _.sortBy(records, 'timestamp');
+ records = sortBy(records, 'timestamp');
tableData.interval = aggregationInterval;
if (aggregationInterval === 'auto') {
// Determine the actual interval to use if aggregating.
@@ -197,7 +199,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
const categoryIdsByJobId: { [key: string]: any } = {};
categoryAnomalies.forEach((anomaly) => {
- if (!_.has(categoryIdsByJobId, anomaly.jobId)) {
+ if (categoryIdsByJobId[anomaly.jobId] === undefined) {
categoryIdsByJobId[anomaly.jobId] = [];
}
if (categoryIdsByJobId[anomaly.jobId].indexOf(anomaly.entityValue) === -1) {
@@ -289,7 +291,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
};
const resp = await callAsInternalUser('search', query);
- const maxScore = _.get(resp, ['aggregations', 'max_score', 'value'], null);
+ const maxScore = get(resp, ['aggregations', 'max_score', 'value'], null);
return { maxScore };
}
@@ -353,7 +355,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
},
});
- const bucketsByJobId: Array<{ key: string; maxTimestamp: { value?: number } }> = _.get(
+ const bucketsByJobId: Array<{ key: string; maxTimestamp: { value?: number } }> = get(
resp,
['aggregations', 'byJobId', 'buckets'],
[]
@@ -387,7 +389,7 @@ export function resultsServiceProvider(mlClusterClient: ILegacyScopedClusterClie
if (resp.hits.total !== 0) {
resp.hits.hits.forEach((hit: any) => {
if (maxExamples) {
- examplesByCategoryId[hit._source.category_id] = _.slice(
+ examplesByCategoryId[hit._source.category_id] = slice(
hit._source.examples,
0,
Math.min(hit._source.examples.length, maxExamples)
diff --git a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap
index ddba7842f1199..66c3aea8acc13 100644
--- a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap
+++ b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap
@@ -30,6 +30,7 @@ Array [
},
]
}
+ data-test-page={0}
data-test-subj="reportJobListing"
isSelectable={true}
itemId="id"
@@ -56,6 +57,7 @@ Array [
>
@@ -366,6 +368,7 @@ Array [
,
diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx
index afcae93a8db16..80ef9311fd0e5 100644
--- a/x-pack/plugins/reporting/public/components/report_listing.tsx
+++ b/x-pack/plugins/reporting/public/components/report_listing.tsx
@@ -513,6 +513,7 @@ class ReportListingUi extends Component
{
isSelectable={true}
onChange={this.onTableChange}
data-test-subj="reportJobListing"
+ data-test-page={this.state.page}
/>
{this.state.selectedJobs.length > 0 ? this.renderDeleteButton() : null}
diff --git a/x-pack/plugins/reporting/server/routes/jobs.ts b/x-pack/plugins/reporting/server/routes/jobs.ts
index 4033719b053ba..e8eac9e577beb 100644
--- a/x-pack/plugins/reporting/server/routes/jobs.ts
+++ b/x-pack/plugins/reporting/server/routes/jobs.ts
@@ -35,7 +35,13 @@ export function registerJobInfoRoutes(reporting: ReportingCore) {
router.get(
{
path: `${MAIN_ENTRY}/list`,
- validate: false,
+ validate: {
+ query: schema.object({
+ page: schema.string({ defaultValue: '0' }),
+ size: schema.string({ defaultValue: '10' }),
+ ids: schema.maybe(schema.string()),
+ }),
+ },
},
userHandler(async (user, context, req, res) => {
// ensure the async dependencies are loaded
@@ -50,7 +56,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) {
page: queryPage = '0',
size: querySize = '10',
ids: queryIds = null,
- } = req.query as ListQuery;
+ } = req.query as ListQuery; // NOTE: type inference is not working here. userHandler breaks it?
const page = parseInt(queryPage, 10) || 0;
const size = Math.min(100, parseInt(querySize, 10) || 10);
const jobIds = queryIds ? queryIds.split(',') : null;
diff --git a/x-pack/plugins/security_solution/common/endpoint/models/event.ts b/x-pack/plugins/security_solution/common/endpoint/models/event.ts
index 30e11819c0272..a0e9be58911c6 100644
--- a/x-pack/plugins/security_solution/common/endpoint/models/event.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/models/event.ts
@@ -55,6 +55,25 @@ export function timestampSafeVersion(event: SafeResolverEvent): string | undefin
: firstNonNullValue(event?.['@timestamp']);
}
+/**
+ * The `@timestamp` for the event, as a `Date` object.
+ * If `@timestamp` couldn't be parsed as a `Date`, returns `undefined`.
+ */
+export function timestampAsDateSafeVersion(event: SafeResolverEvent): Date | undefined {
+ const value = timestampSafeVersion(event);
+ if (value === undefined) {
+ return undefined;
+ }
+
+ const date = new Date(value);
+ // Check if the date is valid
+ if (isFinite(date.getTime())) {
+ return date;
+ } else {
+ return undefined;
+ }
+}
+
export function eventTimestamp(event: ResolverEvent): string | undefined | number {
if (isLegacyEvent(event)) {
return event.endgame.timestamp_utc;
diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx
index e2e3a600a95ff..63b271b8cce78 100644
--- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx
@@ -42,6 +42,9 @@ const FormWrapper = styled.div`
padding-top: ${theme.eui.paddingSizes.xl};
padding-bottom: ${theme.eui.paddingSizes.xl};
+ .euiFlyout {
+ z-index: ${theme.eui.euiZNavigation + 1};
+ }
`}
`;
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/field.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/field.test.tsx
index 30864f246071b..a678deae41542 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/field.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/field.test.tsx
@@ -12,7 +12,7 @@ import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
import {
fields,
getField,
-} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { FieldComponent } from './field';
describe('FieldComponent', () => {
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx
index eca38b9effe1b..eef6e09d496db 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_lists.test.tsx
@@ -11,7 +11,7 @@ import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
// we don't have the types for waitFor just yet, so using "as waitFor" until when we do
import { wait as waitFor } from '@testing-library/react';
-import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { ListSchema } from '../../../lists_plugin_deps';
import { getFoundListSchemaMock } from '../../../../../lists/common/schemas/response/found_list_schema.mock';
import { getListResponseMock } from '../../../../../lists/common/schemas/response/list_schema.mock';
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.test.tsx
index 998ed1f3351c8..94040ccb639be 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match.test.tsx
@@ -12,7 +12,7 @@ import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
import {
fields,
getField,
-} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { AutocompleteFieldMatchComponent } from './field_value_match';
import { useFieldValueAutocomplete } from './hooks/use_field_value_autocomplete';
jest.mock('./hooks/use_field_value_autocomplete');
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.test.tsx
index 0a0281a9c4a51..4074150f76d06 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/field_value_match_any.test.tsx
@@ -12,7 +12,7 @@ import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
import {
fields,
getField,
-} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { AutocompleteFieldMatchAnyComponent } from './field_value_match_any';
import { useFieldValueAutocomplete } from './hooks/use_field_value_autocomplete';
jest.mock('./hooks/use_field_value_autocomplete');
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts b/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts
index 289cdd5e87c00..bbcbcbcf928b3 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/helpers.test.ts
@@ -5,7 +5,7 @@
*/
import '../../../common/mock/match_media';
-import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import {
EXCEPTION_OPERATORS,
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.test.ts b/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.test.ts
index a76b50d11a875..82e9c21f6b839 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.test.ts
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/hooks/use_field_value_autocomplete.test.ts
@@ -13,7 +13,7 @@ import {
} from './use_field_value_autocomplete';
import { useKibana } from '../../../../common/lib/kibana';
import { stubIndexPatternWithFields } from '../../../../../../../../src/plugins/data/common/index_patterns/index_pattern.stub';
-import { getField } from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+import { getField } from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { OperatorTypeEnum } from '../../../../lists_plugin_deps';
jest.mock('../../../../common/lib/kibana');
diff --git a/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.test.tsx b/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.test.tsx
index 737be199e2481..e6f6227811085 100644
--- a/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/autocomplete/operator.test.tsx
@@ -9,7 +9,7 @@ import { mount } from 'enzyme';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui';
-import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+import { getField } from '../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { OperatorComponent } from './operator';
import { isOperator, isNotOperator } from './operators';
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/entry_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/entry_item.test.tsx
index 2a116c4cd8acf..59a5db2a09779 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/entry_item.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/entry_item.test.tsx
@@ -22,7 +22,7 @@ import {
import {
fields,
getField,
-} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { getFoundListSchemaMock } from '../../../../../../lists/common/schemas/response/found_list_schema.mock';
import { getEmptyValue } from '../../empty_value';
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/exception_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/exception_item.test.tsx
index e90639a2c0285..0f9be25e046b2 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/exception_item.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/exception_item.test.tsx
@@ -10,7 +10,7 @@ import { mount } from 'enzyme';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { useKibana } from '../../../../common/lib/kibana';
-import { fields } from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+import { fields } from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
import { getEntryMatchMock } from '../../../../../../lists/common/schemas/types/entry_match.mock';
import { getEntryMatchAnyMock } from '../../../../../../lists/common/schemas/types/entry_match_any.mock';
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/helpers.test.tsx
index 04ab9ee7216f7..9bfd04cc19d72 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/helpers.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/helpers.test.tsx
@@ -6,7 +6,7 @@
import {
fields,
getField,
-} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { getEntryNestedMock } from '../../../../../../lists/common/schemas/types/entry_nested.mock';
import { getEntryMatchMock } from '../../../../../../lists/common/schemas/types/entry_match.mock';
import { getEntryMatchAnyMock } from '../../../../../../lists/common/schemas/types/entry_match_any.mock';
diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/index.test.tsx
index 3fa0e59f9acb0..2d389a7dbcee1 100644
--- a/x-pack/plugins/security_solution/public/common/components/exceptions/builder/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/exceptions/builder/index.test.tsx
@@ -13,7 +13,7 @@ import { wait as waitFor } from '@testing-library/react';
import {
fields,
getField,
-} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks.ts';
+} from '../../../../../../../../src/plugins/data/common/index_patterns/fields/fields.mocks';
import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
import { getEntryMatchAnyMock } from '../../../../../../lists/common/schemas/types/entry_match_any.mock';
diff --git a/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx b/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx
index fbc3d62768d00..e05e3c2e9aeb1 100644
--- a/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/header_global/index.tsx
@@ -41,14 +41,15 @@ const FlexItem = styled(EuiFlexItem)`
`;
FlexItem.displayName = 'FlexItem';
-const FlexGroup = styled(EuiFlexGroup)<{ $globalFullScreen: boolean }>`
- ${({ $globalFullScreen, theme }) => `
+const FlexGroup = styled(EuiFlexGroup)<{ $globalFullScreen: boolean; $hasSibling: boolean }>`
+ ${({ $globalFullScreen, $hasSibling, theme }) => `
border-bottom: ${theme.eui.euiBorderThin};
margin-bottom: 1px;
padding-bottom: 4px;
padding-left: ${theme.eui.paddingSizes.l};
padding-right: ${gutterTimeline};
${$globalFullScreen ? 'display: none;' : ''}
+ ${$hasSibling ? `border-bottom: ${theme.eui.euiBorderThin};` : 'border-bottom-width: 0px;'}
`}
`;
FlexGroup.displayName = 'FlexGroup';
@@ -75,6 +76,7 @@ export const HeaderGlobal = React.memo(({ hideDetectionEngine
diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
index 807f1839973fa..d71242329bcda 100644
--- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
@@ -104,7 +104,7 @@ const StatefulTopNComponent: React.FC = ({
value,
}) => {
const kibana = useKibana();
- const { from, deleteQuery, setQuery, to } = useGlobalTime();
+ const { from, deleteQuery, setQuery, to } = useGlobalTime(false);
const options = getOptions(
timelineId === TimelineId.active ? activeTimelineEventType : undefined
diff --git a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx
index 9d5f1740b0276..07ce3551e3289 100644
--- a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.test.tsx
@@ -8,17 +8,22 @@ import { act, renderHook } from '@testing-library/react-hooks';
import { useGlobalTime } from '.';
+const mockDispatch = jest.fn();
+
jest.mock('react-redux', () => {
const originalModule = jest.requireActual('react-redux');
return {
...originalModule,
- useDispatch: jest.fn().mockReturnValue(jest.fn()),
+ useDispatch: () => mockDispatch,
useSelector: jest.fn().mockReturnValue({ from: 0, to: 0 }),
};
});
describe('useGlobalTime', () => {
+ beforeEach(() => {
+ mockDispatch.mockReset();
+ });
test('returns memoized value', () => {
const { result, rerender } = renderHook(() => useGlobalTime());
@@ -30,4 +35,18 @@ describe('useGlobalTime', () => {
expect(result1.from).toBe(0);
expect(result1.to).toBe(0);
});
+
+ test('clear all queries at unmount', () => {
+ const { rerender } = renderHook(() => useGlobalTime());
+ act(() => rerender());
+ expect(mockDispatch.mock.calls[0][0].type).toEqual(
+ 'x-pack/security_solution/local/inputs/DELETE_ALL_QUERY'
+ );
+ });
+
+ test('do NOT clear all queries at unmount', () => {
+ const { rerender } = renderHook(() => useGlobalTime(false));
+ act(() => rerender());
+ expect(mockDispatch.mock.calls.length).toBe(0);
+ });
});
diff --git a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx
index b63616ecbcf56..52825caf9ce74 100644
--- a/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/containers/use_global_time/index.tsx
@@ -11,7 +11,7 @@ import { inputsSelectors } from '../../store';
import { inputsActions } from '../../store/actions';
import { SetQuery, DeleteQuery } from './types';
-export const useGlobalTime = () => {
+export const useGlobalTime = (clearAllQuery: boolean = true) => {
const dispatch = useDispatch();
const { from, to } = useSelector(inputsSelectors.globalTimeRangeSelector);
const [isInitializing, setIsInitializing] = useState(true);
@@ -32,9 +32,11 @@ export const useGlobalTime = () => {
setIsInitializing(false);
}
return () => {
- dispatch(inputsActions.deleteAllQuery({ id: 'global' }));
+ if (clearAllQuery) {
+ dispatch(inputsActions.deleteAllQuery({ id: 'global' }));
+ }
};
- }, [dispatch, isInitializing]);
+ }, [clearAllQuery, dispatch, isInitializing]);
const memoizedReturn = useMemo(
() => ({
diff --git a/x-pack/plugins/security_solution/public/common/store/actions.ts b/x-pack/plugins/security_solution/public/common/store/actions.ts
index f2072aae1936f..cd8836e38bfef 100644
--- a/x-pack/plugins/security_solution/public/common/store/actions.ts
+++ b/x-pack/plugins/security_solution/public/common/store/actions.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { HostAction } from '../../management/pages/endpoint_hosts/store/action';
+import { EndpointAction } from '../../management/pages/endpoint_hosts/store/action';
import { PolicyListAction } from '../../management/pages/policy/store/policy_list';
import { PolicyDetailsAction } from '../../management/pages/policy/store/policy_details';
@@ -13,4 +13,4 @@ export { dragAndDropActions } from './drag_and_drop';
export { inputsActions } from './inputs';
import { RoutingAction } from './routing';
-export type AppAction = HostAction | RoutingAction | PolicyListAction | PolicyDetailsAction;
+export type AppAction = EndpointAction | RoutingAction | PolicyListAction | PolicyDetailsAction;
diff --git a/x-pack/plugins/security_solution/public/management/common/constants.ts b/x-pack/plugins/security_solution/public/management/common/constants.ts
index b07c47a398049..88396cc24a5e2 100644
--- a/x-pack/plugins/security_solution/public/management/common/constants.ts
+++ b/x-pack/plugins/security_solution/public/management/common/constants.ts
@@ -10,7 +10,7 @@ import { SecurityPageName } from '../../app/types';
// --[ ROUTING ]---------------------------------------------------------------------------
export const MANAGEMENT_APP_ID = `${APP_ID}:${SecurityPageName.administration}`;
export const MANAGEMENT_ROUTING_ROOT_PATH = '';
-export const MANAGEMENT_ROUTING_HOSTS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.hosts})`;
+export const MANAGEMENT_ROUTING_ENDPOINTS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.endpoints})`;
export const MANAGEMENT_ROUTING_POLICIES_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.policies})`;
export const MANAGEMENT_ROUTING_POLICY_DETAILS_PATH = `${MANAGEMENT_ROUTING_ROOT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId`;
@@ -21,5 +21,5 @@ export const MANAGEMENT_STORE_GLOBAL_NAMESPACE: ManagementStoreGlobalNamespace =
export const MANAGEMENT_STORE_POLICY_LIST_NAMESPACE = 'policyList';
/** Namespace within the Management state where policy details state is maintained */
export const MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE = 'policyDetails';
-/** Namespace within the Management state where hosts state is maintained */
-export const MANAGEMENT_STORE_HOSTS_NAMESPACE = 'hosts';
+/** Namespace within the Management state where endpoint-host state is maintained */
+export const MANAGEMENT_STORE_ENDPOINTS_NAMESPACE = 'endpoints';
diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts
index eeb1533f57a67..ea162422abb6f 100644
--- a/x-pack/plugins/security_solution/public/management/common/routing.ts
+++ b/x-pack/plugins/security_solution/public/management/common/routing.ts
@@ -10,13 +10,13 @@ import { generatePath } from 'react-router-dom';
import querystring from 'querystring';
import {
- MANAGEMENT_ROUTING_HOSTS_PATH,
+ MANAGEMENT_ROUTING_ENDPOINTS_PATH,
MANAGEMENT_ROUTING_POLICIES_PATH,
MANAGEMENT_ROUTING_POLICY_DETAILS_PATH,
} from './constants';
import { AdministrationSubTab } from '../types';
import { appendSearch } from '../../common/components/link_to/helpers';
-import { HostIndexUIQueryParams } from '../pages/endpoint_hosts/types';
+import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types';
// Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150
type ExactKeys = Exclude extends never ? T1 : never;
@@ -31,42 +31,44 @@ const querystringStringify: (
params: Exact
) => string = querystring.stringify;
-/** Make `selected_host` required */
-type HostDetailsUrlProps = Omit &
- Required>;
+/** Make `selected_endpoint` required */
+type EndpointDetailsUrlProps = Omit &
+ Required>;
-export const getHostListPath = (
- props: { name: 'default' | 'hostList' } & HostIndexUIQueryParams,
+export const getEndpointListPath = (
+ props: { name: 'default' | 'endpointList' } & EndpointIndexUIQueryParams,
search?: string
) => {
const { name, ...queryParams } = props;
- const urlQueryParams = querystringStringify(
+ const urlQueryParams = querystringStringify(
queryParams
);
const urlSearch = `${urlQueryParams && !isEmpty(search) ? '&' : ''}${search ?? ''}`;
- if (name === 'hostList') {
- return `${generatePath(MANAGEMENT_ROUTING_HOSTS_PATH, {
- tabName: AdministrationSubTab.hosts,
+ if (name === 'endpointList') {
+ return `${generatePath(MANAGEMENT_ROUTING_ENDPOINTS_PATH, {
+ tabName: AdministrationSubTab.endpoints,
})}${appendSearch(`${urlQueryParams ? `${urlQueryParams}${urlSearch}` : urlSearch}`)}`;
}
return `${appendSearch(`${urlQueryParams ? `${urlQueryParams}${urlSearch}` : urlSearch}`)}`;
};
-export const getHostDetailsPath = (
- props: { name: 'hostDetails' | 'hostPolicyResponse' } & HostIndexUIQueryParams &
- HostDetailsUrlProps,
+export const getEndpointDetailsPath = (
+ props: { name: 'endpointDetails' | 'endpointPolicyResponse' } & EndpointIndexUIQueryParams &
+ EndpointDetailsUrlProps,
search?: string
) => {
const { name, ...queryParams } = props;
- queryParams.show = (props.name === 'hostPolicyResponse'
+ queryParams.show = (props.name === 'endpointPolicyResponse'
? 'policy_response'
- : '') as HostIndexUIQueryParams['show'];
- const urlQueryParams = querystringStringify(queryParams);
+ : '') as EndpointIndexUIQueryParams['show'];
+ const urlQueryParams = querystringStringify(
+ queryParams
+ );
const urlSearch = `${urlQueryParams && !isEmpty(search) ? '&' : ''}${search ?? ''}`;
- return `${generatePath(MANAGEMENT_ROUTING_HOSTS_PATH, {
- tabName: AdministrationSubTab.hosts,
+ return `${generatePath(MANAGEMENT_ROUTING_ENDPOINTS_PATH, {
+ tabName: AdministrationSubTab.endpoints,
})}${appendSearch(`${urlQueryParams ? `${urlQueryParams}${urlSearch}` : urlSearch}`)}`;
};
diff --git a/x-pack/plugins/security_solution/public/management/common/translations.ts b/x-pack/plugins/security_solution/public/management/common/translations.ts
index 70ccf715eaa09..03f6a80ef99a4 100644
--- a/x-pack/plugins/security_solution/public/management/common/translations.ts
+++ b/x-pack/plugins/security_solution/public/management/common/translations.ts
@@ -6,8 +6,8 @@
import { i18n } from '@kbn/i18n';
-export const HOSTS_TAB = i18n.translate('xpack.securitySolution.hostsTab', {
- defaultMessage: 'Hosts',
+export const ENDPOINTS_TAB = i18n.translate('xpack.securitySolution.endpointsTab', {
+ defaultMessage: 'Endpoints',
});
export const POLICIES_TAB = i18n.translate('xpack.securitySolution.policiesTab', {
diff --git a/x-pack/plugins/security_solution/public/management/components/management_empty_state.tsx b/x-pack/plugins/security_solution/public/management/components/management_empty_state.tsx
index a4518d1a1f493..4617865d6aa6d 100644
--- a/x-pack/plugins/security_solution/public/management/components/management_empty_state.tsx
+++ b/x-pack/plugins/security_solution/public/management/components/management_empty_state.tsx
@@ -116,7 +116,7 @@ const PolicyEmptyState = React.memo<{
);
});
-const HostsEmptyState = React.memo<{
+const EndpointsEmptyState = React.memo<{
loading: boolean;
onActionClick: (event: MouseEvent) => void;
actionDisabled: boolean;
@@ -126,14 +126,14 @@ const HostsEmptyState = React.memo<{
const policySteps = useMemo(
() => [
{
- title: i18n.translate('xpack.securitySolution.endpoint.hostList.stepOneTitle', {
+ title: i18n.translate('xpack.securitySolution.endpoint.list.stepOneTitle', {
defaultMessage: 'Select the integration you want to use',
}),
children: (
<>
@@ -151,7 +151,7 @@ const HostsEmptyState = React.memo<{
return loading ? (
@@ -159,7 +159,7 @@ const HostsEmptyState = React.memo<{
list
) : (
);
@@ -169,7 +169,7 @@ const HostsEmptyState = React.memo<{
),
},
{
- title: i18n.translate('xpack.securitySolution.endpoint.hostList.stepTwoTitle', {
+ title: i18n.translate('xpack.securitySolution.endpoint.list.stepTwoTitle', {
defaultMessage:
'Enroll your agents enabled with Endpoint Security through Ingest Manager',
}),
@@ -179,7 +179,7 @@ const HostsEmptyState = React.memo<{
@@ -211,13 +211,13 @@ const HostsEmptyState = React.memo<{
steps={policySteps}
headerComponent={
}
bodyComponent={
}
@@ -265,7 +265,7 @@ const ManagementEmptyState = React.memo<{
});
PolicyEmptyState.displayName = 'PolicyEmptyState';
-HostsEmptyState.displayName = 'HostsEmptyState';
+EndpointsEmptyState.displayName = 'HostsEmptyState';
ManagementEmptyState.displayName = 'ManagementEmptyState';
-export { PolicyEmptyState, HostsEmptyState };
+export { PolicyEmptyState, EndpointsEmptyState as HostsEmptyState };
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx
index a970edd4d30f4..23e55301d22cb 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx
@@ -6,20 +6,20 @@
import { Switch, Route } from 'react-router-dom';
import React, { memo } from 'react';
-import { HostList } from './view';
-import { MANAGEMENT_ROUTING_HOSTS_PATH } from '../../common/constants';
+import { EndpointList } from './view';
+import { MANAGEMENT_ROUTING_ENDPOINTS_PATH } from '../../common/constants';
import { NotFoundPage } from '../../../app/404';
/**
* Provides the routing container for the hosts related views
*/
-export const HostsContainer = memo(() => {
+export const EndpointsContainer = memo(() => {
return (
-
+
);
});
-HostsContainer.displayName = 'HostsContainer';
+EndpointsContainer.displayName = 'EndpointsContainer';
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/routes.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/routes.tsx
index 3f92358b93d56..727d2715f0974 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/routes.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/routes.tsx
@@ -7,12 +7,12 @@
import React from 'react';
import { Route, Switch } from 'react-router-dom';
-import { HostList } from './view';
+import { EndpointList } from './view';
export const EndpointHostsRoutes: React.FC = () => (
-
-
+
+
);
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts
index 4a4326d5b2919..2e188af41d2d7 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts
@@ -12,35 +12,35 @@ import {
import { ServerApiError } from '../../../../common/types';
import { GetPolicyListResponse } from '../../policy/types';
import { GetPackagesResponse } from '../../../../../../ingest_manager/common';
-import { HostState } from '../types';
+import { EndpointState } from '../types';
-interface ServerReturnedHostList {
- type: 'serverReturnedHostList';
+interface ServerReturnedEndpointList {
+ type: 'serverReturnedEndpointList';
payload: HostResultList;
}
-interface ServerFailedToReturnHostList {
- type: 'serverFailedToReturnHostList';
+interface ServerFailedToReturnEndpointList {
+ type: 'serverFailedToReturnEndpointList';
payload: ServerApiError;
}
-interface ServerReturnedHostDetails {
- type: 'serverReturnedHostDetails';
+interface ServerReturnedEndpointDetails {
+ type: 'serverReturnedEndpointDetails';
payload: HostInfo;
}
-interface ServerFailedToReturnHostDetails {
- type: 'serverFailedToReturnHostDetails';
+interface ServerFailedToReturnEndpointDetails {
+ type: 'serverFailedToReturnEndpointDetails';
payload: ServerApiError;
}
-interface ServerReturnedHostPolicyResponse {
- type: 'serverReturnedHostPolicyResponse';
+interface ServerReturnedEndpointPolicyResponse {
+ type: 'serverReturnedEndpointPolicyResponse';
payload: GetHostPolicyResponse;
}
-interface ServerFailedToReturnHostPolicyResponse {
- type: 'serverFailedToReturnHostPolicyResponse';
+interface ServerFailedToReturnEndpointPolicyResponse {
+ type: 'serverFailedToReturnEndpointPolicyResponse';
payload: ServerApiError;
}
@@ -63,8 +63,8 @@ interface UserSelectedEndpointPolicy {
};
}
-interface ServerCancelledHostListLoading {
- type: 'serverCancelledHostListLoading';
+interface ServerCancelledEndpointListLoading {
+ type: 'serverCancelledEndpointListLoading';
}
interface ServerCancelledPolicyItemsLoading {
@@ -76,28 +76,28 @@ interface ServerReturnedEndpointPackageInfo {
payload: GetPackagesResponse['response'][0];
}
-interface ServerReturnedHostNonExistingPolicies {
- type: 'serverReturnedHostNonExistingPolicies';
- payload: HostState['nonExistingPolicies'];
+interface ServerReturnedEndpointNonExistingPolicies {
+ type: 'serverReturnedEndpointNonExistingPolicies';
+ payload: EndpointState['nonExistingPolicies'];
}
-interface ServerReturnedHostExistValue {
- type: 'serverReturnedHostExistValue';
+interface ServerReturnedEndpointExistValue {
+ type: 'serverReturnedEndpointExistValue';
payload: boolean;
}
-export type HostAction =
- | ServerReturnedHostList
- | ServerFailedToReturnHostList
- | ServerReturnedHostDetails
- | ServerFailedToReturnHostDetails
- | ServerReturnedHostPolicyResponse
- | ServerFailedToReturnHostPolicyResponse
+export type EndpointAction =
+ | ServerReturnedEndpointList
+ | ServerFailedToReturnEndpointList
+ | ServerReturnedEndpointDetails
+ | ServerFailedToReturnEndpointDetails
+ | ServerReturnedEndpointPolicyResponse
+ | ServerFailedToReturnEndpointPolicyResponse
| ServerReturnedPoliciesForOnboarding
| ServerFailedToReturnPoliciesForOnboarding
| UserSelectedEndpointPolicy
- | ServerCancelledHostListLoading
- | ServerReturnedHostExistValue
+ | ServerCancelledEndpointListLoading
+ | ServerReturnedEndpointExistValue
| ServerCancelledPolicyItemsLoading
| ServerReturnedEndpointPackageInfo
- | ServerReturnedHostNonExistingPolicies;
+ | ServerReturnedEndpointNonExistingPolicies;
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/host_pagination.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts
similarity index 80%
rename from x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/host_pagination.test.ts
rename to x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts
index 533b14e50f3dd..0fd970f4bed12 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/host_pagination.test.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts
@@ -13,41 +13,41 @@ import { coreMock } from '../../../../../../../../src/core/public/mocks';
import { HostResultList, AppLocation } from '../../../../../common/endpoint/types';
import { DepsStartMock, depsStartMock } from '../../../../common/mock/endpoint';
-import { hostMiddlewareFactory } from './middleware';
+import { endpointMiddlewareFactory } from './middleware';
-import { hostListReducer } from './reducer';
+import { endpointListReducer } from './reducer';
import { uiQueryParams } from './selectors';
-import { mockHostResultList } from './mock_host_result_list';
-import { HostState, HostIndexUIQueryParams } from '../types';
+import { mockEndpointResultList } from './mock_endpoint_result_list';
+import { EndpointState, EndpointIndexUIQueryParams } from '../types';
import {
MiddlewareActionSpyHelper,
createSpyMiddleware,
} from '../../../../common/store/test_utils';
-import { getHostListPath } from '../../../common/routing';
+import { getEndpointListPath } from '../../../common/routing';
-describe('host list pagination: ', () => {
+describe('endpoint list pagination: ', () => {
let fakeCoreStart: jest.Mocked;
let depsStart: DepsStartMock;
let fakeHttpServices: jest.Mocked;
let history: History;
let store: Store;
- let queryParams: () => HostIndexUIQueryParams;
+ let queryParams: () => EndpointIndexUIQueryParams;
let waitForAction: MiddlewareActionSpyHelper['waitForAction'];
let actionSpyMiddleware;
const getEndpointListApiResponse = (): HostResultList => {
- return mockHostResultList({ request_page_size: 1, request_page_index: 1, total: 10 });
+ return mockEndpointResultList({ request_page_size: 1, request_page_index: 1, total: 10 });
};
- let historyPush: (params: HostIndexUIQueryParams) => void;
+ let historyPush: (params: EndpointIndexUIQueryParams) => void;
beforeEach(() => {
fakeCoreStart = coreMock.createStart();
depsStart = depsStartMock();
fakeHttpServices = fakeCoreStart.http as jest.Mocked;
history = createBrowserHistory();
- const middleware = hostMiddlewareFactory(fakeCoreStart, depsStart);
- ({ actionSpyMiddleware, waitForAction } = createSpyMiddleware());
- store = createStore(hostListReducer, applyMiddleware(middleware, actionSpyMiddleware));
+ const middleware = endpointMiddlewareFactory(fakeCoreStart, depsStart);
+ ({ actionSpyMiddleware, waitForAction } = createSpyMiddleware());
+ store = createStore(endpointListReducer, applyMiddleware(middleware, actionSpyMiddleware));
history.listen((location) => {
store.dispatch({ type: 'userChangedUrl', payload: location });
@@ -55,12 +55,12 @@ describe('host list pagination: ', () => {
queryParams = () => uiQueryParams(store.getState());
- historyPush = (nextQueryParams: HostIndexUIQueryParams): void => {
- return history.push(getHostListPath({ name: 'hostList', ...nextQueryParams }));
+ historyPush = (nextQueryParams: EndpointIndexUIQueryParams): void => {
+ return history.push(getEndpointListPath({ name: 'endpointList', ...nextQueryParams }));
};
});
- describe('when the user enteres the host list for the first time', () => {
+ describe('when the user enteres the endpoint list for the first time', () => {
it('the api is called with page_index and page_size defaulting to 0 and 10 respectively', async () => {
const apiResponse = getEndpointListApiResponse();
fakeHttpServices.post.mockResolvedValue(apiResponse);
@@ -70,10 +70,10 @@ describe('host list pagination: ', () => {
type: 'userChangedUrl',
payload: {
...history.location,
- pathname: getHostListPath({ name: 'hostList' }),
+ pathname: getEndpointListPath({ name: 'endpointList' }),
},
});
- await waitForAction('serverReturnedHostList');
+ await waitForAction('serverReturnedEndpointList');
expect(fakeHttpServices.post).toHaveBeenCalledWith('/api/endpoint/metadata', {
body: JSON.stringify({
paging_properties: [{ page_index: '0' }, { page_size: '10' }],
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
index 8ff4ad5a043b5..b3ab3443809c8 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
@@ -5,24 +5,24 @@
*/
import { createStore, Dispatch, Store } from 'redux';
-import { HostState } from '../types';
+import { EndpointState } from '../types';
import { listData } from './selectors';
-import { mockHostResultList } from './mock_host_result_list';
-import { HostAction } from './action';
-import { hostListReducer } from './reducer';
+import { mockEndpointResultList } from './mock_endpoint_result_list';
+import { EndpointAction } from './action';
+import { endpointListReducer } from './reducer';
-describe('HostList store concerns', () => {
- let store: Store;
- let dispatch: Dispatch;
+describe('EndpointList store concerns', () => {
+ let store: Store;
+ let dispatch: Dispatch;
const createTestStore = () => {
- store = createStore(hostListReducer);
+ store = createStore(endpointListReducer);
dispatch = store.dispatch;
};
const loadDataToStore = () => {
dispatch({
- type: 'serverReturnedHostList',
- payload: mockHostResultList({ request_page_size: 1, request_page_index: 1, total: 10 }),
+ type: 'serverReturnedEndpointList',
+ payload: mockEndpointResultList({ request_page_size: 1, request_page_index: 1, total: 10 }),
});
};
@@ -51,18 +51,18 @@ describe('HostList store concerns', () => {
policyItemsLoading: false,
endpointPackageInfo: undefined,
nonExistingPolicies: {},
- hostsExist: true,
+ endpointsExist: true,
});
});
- test('it handles `serverReturnedHostList', () => {
- const payload = mockHostResultList({
+ test('it handles `serverReturnedEndpointList', () => {
+ const payload = mockEndpointResultList({
request_page_size: 1,
request_page_index: 1,
total: 10,
});
dispatch({
- type: 'serverReturnedHostList',
+ type: 'serverReturnedEndpointList',
payload,
});
@@ -80,7 +80,7 @@ describe('HostList store concerns', () => {
loadDataToStore();
});
- test('it selects `hostListData`', () => {
+ test('it selects `endpointListData`', () => {
const currentState = store.getState();
expect(listData(currentState)).toEqual(currentState.hosts);
});
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts
index 1c5c4fbac51ba..77ade5bcc6971 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts
@@ -16,36 +16,36 @@ import {
} from '../../../../common/store/test_utils';
import { Immutable, HostResultList } from '../../../../../common/endpoint/types';
import { AppAction } from '../../../../common/store/actions';
-import { mockHostResultList } from './mock_host_result_list';
+import { mockEndpointResultList } from './mock_endpoint_result_list';
import { listData } from './selectors';
-import { HostState } from '../types';
-import { hostListReducer } from './reducer';
-import { hostMiddlewareFactory } from './middleware';
-import { getHostListPath } from '../../../common/routing';
+import { EndpointState } from '../types';
+import { endpointListReducer } from './reducer';
+import { endpointMiddlewareFactory } from './middleware';
+import { getEndpointListPath } from '../../../common/routing';
-describe('host list middleware', () => {
+describe('endpoint list middleware', () => {
let fakeCoreStart: jest.Mocked;
let depsStart: DepsStartMock;
let fakeHttpServices: jest.Mocked;
- type HostListStore = Store, Immutable>;
- let store: HostListStore;
- let getState: HostListStore['getState'];
- let dispatch: HostListStore['dispatch'];
+ type EndpointListStore = Store, Immutable>;
+ let store: EndpointListStore;
+ let getState: EndpointListStore['getState'];
+ let dispatch: EndpointListStore['dispatch'];
let waitForAction: MiddlewareActionSpyHelper['waitForAction'];
let actionSpyMiddleware;
let history: History;
const getEndpointListApiResponse = (): HostResultList => {
- return mockHostResultList({ request_page_size: 1, request_page_index: 1, total: 10 });
+ return mockEndpointResultList({ request_page_size: 1, request_page_index: 1, total: 10 });
};
beforeEach(() => {
fakeCoreStart = coreMock.createStart({ basePath: '/mock' });
depsStart = depsStartMock();
fakeHttpServices = fakeCoreStart.http as jest.Mocked;
- ({ actionSpyMiddleware, waitForAction } = createSpyMiddleware());
+ ({ actionSpyMiddleware, waitForAction } = createSpyMiddleware());
store = createStore(
- hostListReducer,
- applyMiddleware(hostMiddlewareFactory(fakeCoreStart, depsStart), actionSpyMiddleware)
+ endpointListReducer,
+ applyMiddleware(endpointMiddlewareFactory(fakeCoreStart, depsStart), actionSpyMiddleware)
);
getState = store.getState;
dispatch = store.dispatch;
@@ -60,10 +60,10 @@ describe('host list middleware', () => {
type: 'userChangedUrl',
payload: {
...history.location,
- pathname: getHostListPath({ name: 'hostList' }),
+ pathname: getEndpointListPath({ name: 'endpointList' }),
},
});
- await waitForAction('serverReturnedHostList');
+ await waitForAction('serverReturnedEndpointList');
expect(fakeHttpServices.post).toHaveBeenCalledWith('/api/endpoint/metadata', {
body: JSON.stringify({
paging_properties: [{ page_index: '0' }, { page_size: '10' }],
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
index 74bebf211258a..fa2dbe084c1a4 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
@@ -9,14 +9,14 @@ import { HostInfo, HostResultList } from '../../../../../common/endpoint/types';
import { GetPolicyListResponse } from '../../policy/types';
import { ImmutableMiddlewareFactory } from '../../../../common/store';
import {
- isOnHostPage,
- hasSelectedHost,
+ isOnEndpointPage,
+ hasSelectedEndpoint,
uiQueryParams,
listData,
endpointPackageInfo,
nonExistingPolicies,
} from './selectors';
-import { HostState } from '../types';
+import { EndpointState } from '../types';
import {
sendGetEndpointSpecificPackageConfigs,
sendGetEndpointSecurityPackage,
@@ -24,16 +24,16 @@ import {
} from '../../policy/store/policy_list/services/ingest';
import { AGENT_CONFIG_SAVED_OBJECT_TYPE } from '../../../../../../ingest_manager/common';
-export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (coreStart) => {
+export const endpointMiddlewareFactory: ImmutableMiddlewareFactory = (coreStart) => {
return ({ getState, dispatch }) => (next) => async (action) => {
next(action);
const state = getState();
- // Host list
+ // Endpoint list
if (
action.type === 'userChangedUrl' &&
- isOnHostPage(state) &&
- hasSelectedHost(state) !== true
+ isOnEndpointPage(state) &&
+ hasSelectedEndpoint(state) !== true
) {
if (!endpointPackageInfo(state)) {
sendGetEndpointSecurityPackage(coreStart.http)
@@ -50,30 +50,30 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
}
const { page_index: pageIndex, page_size: pageSize } = uiQueryParams(state);
- let hostResponse;
+ let endpointResponse;
try {
- hostResponse = await coreStart.http.post('/api/endpoint/metadata', {
+ endpointResponse = await coreStart.http.post('/api/endpoint/metadata', {
body: JSON.stringify({
paging_properties: [{ page_index: pageIndex }, { page_size: pageSize }],
}),
});
- hostResponse.request_page_index = Number(pageIndex);
+ endpointResponse.request_page_index = Number(pageIndex);
dispatch({
- type: 'serverReturnedHostList',
- payload: hostResponse,
+ type: 'serverReturnedEndpointList',
+ payload: endpointResponse,
});
- getNonExistingPoliciesForHostsList(
+ getNonExistingPoliciesForEndpointsList(
coreStart.http,
- hostResponse.hosts,
+ endpointResponse.hosts,
nonExistingPolicies(state)
)
.then((missingPolicies) => {
if (missingPolicies !== undefined) {
dispatch({
- type: 'serverReturnedHostNonExistingPolicies',
+ type: 'serverReturnedEndpointNonExistingPolicies',
payload: missingPolicies,
});
}
@@ -83,24 +83,24 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
.catch((error) => console.error(error));
} catch (error) {
dispatch({
- type: 'serverFailedToReturnHostList',
+ type: 'serverFailedToReturnEndpointList',
payload: error,
});
}
- // No hosts, so we should check to see if there are policies for onboarding
- if (hostResponse && hostResponse.hosts.length === 0) {
+ // No endpoints, so we should check to see if there are policies for onboarding
+ if (endpointResponse && endpointResponse.hosts.length === 0) {
const http = coreStart.http;
// The original query to the list could have had an invalid param (ex. invalid page_size),
- // so we check first if hosts actually do exist before pulling in data for the onboarding
+ // so we check first if endpoints actually do exist before pulling in data for the onboarding
// messages.
- if (await doHostsExist(http)) {
+ if (await doEndpointsExist(http)) {
return;
}
dispatch({
- type: 'serverReturnedHostExistValue',
+ type: 'serverReturnedEndpointExistValue',
payload: false,
});
@@ -135,13 +135,13 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
}
}
- // Host Details
- if (action.type === 'userChangedUrl' && hasSelectedHost(state) === true) {
+ // Endpoint Details
+ if (action.type === 'userChangedUrl' && hasSelectedEndpoint(state) === true) {
dispatch({
type: 'serverCancelledPolicyItemsLoading',
});
- // If user navigated directly to a host details page, load the host list
+ // If user navigated directly to a endpoint details page, load the endpoint list
if (listData(state).length === 0) {
const { page_index: pageIndex, page_size: pageSize } = uiQueryParams(state);
try {
@@ -152,11 +152,11 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
});
response.request_page_index = Number(pageIndex);
dispatch({
- type: 'serverReturnedHostList',
+ type: 'serverReturnedEndpointList',
payload: response,
});
- getNonExistingPoliciesForHostsList(
+ getNonExistingPoliciesForEndpointsList(
coreStart.http,
response.hosts,
nonExistingPolicies(state)
@@ -164,7 +164,7 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
.then((missingPolicies) => {
if (missingPolicies !== undefined) {
dispatch({
- type: 'serverReturnedHostNonExistingPolicies',
+ type: 'serverReturnedEndpointNonExistingPolicies',
payload: missingPolicies,
});
}
@@ -174,31 +174,35 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
.catch((error) => console.error(error));
} catch (error) {
dispatch({
- type: 'serverFailedToReturnHostList',
+ type: 'serverFailedToReturnEndpointList',
payload: error,
});
}
} else {
dispatch({
- type: 'serverCancelledHostListLoading',
+ type: 'serverCancelledEndpointListLoading',
});
}
- // call the host details api
- const { selected_host: selectedHost } = uiQueryParams(state);
+ // call the endpoint details api
+ const { selected_endpoint: selectedEndpoint } = uiQueryParams(state);
try {
const response = await coreStart.http.get(
- `/api/endpoint/metadata/${selectedHost}`
+ `/api/endpoint/metadata/${selectedEndpoint}`
);
dispatch({
- type: 'serverReturnedHostDetails',
+ type: 'serverReturnedEndpointDetails',
payload: response,
});
- getNonExistingPoliciesForHostsList(coreStart.http, [response], nonExistingPolicies(state))
+ getNonExistingPoliciesForEndpointsList(
+ coreStart.http,
+ [response],
+ nonExistingPolicies(state)
+ )
.then((missingPolicies) => {
if (missingPolicies !== undefined) {
dispatch({
- type: 'serverReturnedHostNonExistingPolicies',
+ type: 'serverReturnedEndpointNonExistingPolicies',
payload: missingPolicies,
});
}
@@ -208,7 +212,7 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
.catch((error) => console.error(error));
} catch (error) {
dispatch({
- type: 'serverFailedToReturnHostDetails',
+ type: 'serverFailedToReturnEndpointDetails',
payload: error,
});
}
@@ -216,15 +220,15 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
// call the policy response api
try {
const policyResponse = await coreStart.http.get(`/api/endpoint/policy_response`, {
- query: { hostId: selectedHost },
+ query: { hostId: selectedEndpoint },
});
dispatch({
- type: 'serverReturnedHostPolicyResponse',
+ type: 'serverReturnedEndpointPolicyResponse',
payload: policyResponse,
});
} catch (error) {
dispatch({
- type: 'serverFailedToReturnHostPolicyResponse',
+ type: 'serverFailedToReturnEndpointPolicyResponse',
payload: error,
});
}
@@ -232,11 +236,11 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = (cor
};
};
-const getNonExistingPoliciesForHostsList = async (
+const getNonExistingPoliciesForEndpointsList = async (
http: HttpStart,
hosts: HostResultList['hosts'],
- currentNonExistingPolicies: HostState['nonExistingPolicies']
-): Promise => {
+ currentNonExistingPolicies: EndpointState['nonExistingPolicies']
+): Promise => {
if (hosts.length === 0) {
return;
}
@@ -266,14 +270,14 @@ const getNonExistingPoliciesForHostsList = async (
)})`,
},
})
- ).items.reduce((list, agentConfig) => {
+ ).items.reduce((list, agentConfig) => {
(agentConfig.package_configs as string[]).forEach((packageConfig) => {
list[packageConfig as string] = true;
});
return list;
}, {});
- const nonExisting = policyIdsToCheck.reduce(
+ const nonExisting = policyIdsToCheck.reduce(
(list, policyId) => {
if (policiesFound[policyId]) {
return list;
@@ -291,7 +295,7 @@ const getNonExistingPoliciesForHostsList = async (
return nonExisting;
};
-const doHostsExist = async (http: HttpStart): Promise => {
+const doEndpointsExist = async (http: HttpStart): Promise => {
try {
return (
(
@@ -304,7 +308,7 @@ const doHostsExist = async (http: HttpStart): Promise => {
);
} catch (error) {
// eslint-disable-next-line no-console
- console.error(`error while trying to check if hosts exist`);
+ console.error(`error while trying to check if endpoints exist`);
// eslint-disable-next-line no-console
console.error(error);
}
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_host_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
similarity index 79%
rename from x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_host_result_list.ts
rename to x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
index b69e5c5cd0e65..2f0b66624f379 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_host_result_list.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
@@ -26,7 +26,7 @@ import { GetPolicyListResponse } from '../../policy/types';
const generator = new EndpointDocGenerator('seed');
-export const mockHostResultList: (options?: {
+export const mockEndpointResultList: (options?: {
total?: number;
request_page_size?: number;
request_page_index?: number;
@@ -62,7 +62,7 @@ export const mockHostResultList: (options?: {
/**
* returns a mocked API response for retrieving a single host metadata
*/
-export const mockHostDetailsApiResult = (): HostInfo => {
+export const mockEndpointDetailsApiResult = (): HostInfo => {
return {
metadata: generator.generateHostMetadata(),
host_status: HostStatus.ERROR,
@@ -73,14 +73,14 @@ export const mockHostDetailsApiResult = (): HostInfo => {
* Mock API handlers used by the Endpoint Host list. It also sets up a list of
* API handlers for Host details based on a list of Host results.
*/
-const hostListApiPathHandlerMocks = ({
- hostsResults = mockHostResultList({ total: 3 }).hosts,
+const endpointListApiPathHandlerMocks = ({
+ endpointsResults = mockEndpointResultList({ total: 3 }).hosts,
epmPackages = [generator.generateEpmPackage()],
endpointPackageConfigs = [],
policyResponse = generator.generatePolicyResponse(),
}: {
/** route handlers will be setup for each individual host in this array */
- hostsResults?: HostResultList['hosts'];
+ endpointsResults?: HostResultList['hosts'];
epmPackages?: GetPackagesResponse['response'];
endpointPackageConfigs?: GetPolicyListResponse['items'];
policyResponse?: HostPolicyResponse;
@@ -94,17 +94,17 @@ const hostListApiPathHandlerMocks = ({
};
},
- // host list
+ // endpoint list
'/api/endpoint/metadata': (): HostResultList => {
return {
- hosts: hostsResults,
+ hosts: endpointsResults,
request_page_size: 10,
request_page_index: 0,
- total: hostsResults?.length || 0,
+ total: endpointsResults?.length || 0,
};
},
- // Do policies referenced in host list exist
+ // Do policies referenced in endpoint list exist
// just returns 1 single agent config that includes all of the packageConfig IDs provided
[INGEST_API_AGENT_CONFIGS]: (): GetAgentConfigsResponse => {
const agentConfig = generator.generateAgentConfig();
@@ -137,9 +137,9 @@ const hostListApiPathHandlerMocks = ({
},
};
- // Build a GET route handler for each host details based on the list of Hosts passed on input
- if (hostsResults) {
- hostsResults.forEach((host) => {
+ // Build a GET route handler for each endpoint details based on the list of Endpoints passed on input
+ if (endpointsResults) {
+ endpointsResults.forEach((host) => {
// @ts-expect-error
apiHandlers[`/api/endpoint/metadata/${host.metadata.host.id}`] = () => host;
});
@@ -149,33 +149,36 @@ const hostListApiPathHandlerMocks = ({
};
/**
- * Sets up mock impelementations in support of the Hosts list view
+ * Sets up mock impelementations in support of the Endpoints list view
*
* @param mockedHttpService
- * @param hostsResults
+ * @param endpointsResults
* @param pathHandlersOptions
*/
-export const setHostListApiMockImplementation: (
+export const setEndpointListApiMockImplementation: (
mockedHttpService: jest.Mocked,
- apiResponses?: Parameters[0]
+ apiResponses?: Parameters[0]
) => void = (
mockedHttpService,
- { hostsResults = mockHostResultList({ total: 3 }).hosts, ...pathHandlersOptions } = {}
+ { endpointsResults = mockEndpointResultList({ total: 3 }).hosts, ...pathHandlersOptions } = {}
) => {
- const apiHandlers = hostListApiPathHandlerMocks({ ...pathHandlersOptions, hostsResults });
+ const apiHandlers = endpointListApiPathHandlerMocks({
+ ...pathHandlersOptions,
+ endpointsResults,
+ });
mockedHttpService.post
.mockImplementation(async (...args) => {
throw new Error(`un-expected call to http.post: ${args}`);
})
- // First time called, return list of hosts
+ // First time called, return list of endpoints
.mockImplementationOnce(async () => {
return apiHandlers['/api/endpoint/metadata']();
});
- // If the hosts list results is zero, then mock the second call to `/metadata` to return
- // empty list - indicating there are no hosts currently present on the system
- if (!hostsResults.length) {
+ // If the endpoints list results is zero, then mock the second call to `/metadata` to return
+ // empty list - indicating there are no endpoints currently present on the system
+ if (!endpointsResults.length) {
mockedHttpService.post.mockImplementationOnce(async () => {
return apiHandlers['/api/endpoint/metadata']();
});
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
index e54f7df4d4f75..d4fe3310eac0a 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
@@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { isOnHostPage, hasSelectedHost } from './selectors';
-import { HostState } from '../types';
+import { isOnEndpointPage, hasSelectedEndpoint } from './selectors';
+import { EndpointState } from '../types';
import { AppAction } from '../../../../common/store/actions';
import { ImmutableReducer } from '../../../../common/store';
import { Immutable } from '../../../../../common/endpoint/types';
-export const initialHostListState: Immutable = {
+export const initialEndpointListState: Immutable = {
hosts: [],
pageSize: 10,
pageIndex: 0,
@@ -29,15 +29,15 @@ export const initialHostListState: Immutable = {
policyItemsLoading: false,
endpointPackageInfo: undefined,
nonExistingPolicies: {},
- hostsExist: true,
+ endpointsExist: true,
};
/* eslint-disable-next-line complexity */
-export const hostListReducer: ImmutableReducer = (
- state = initialHostListState,
+export const endpointListReducer: ImmutableReducer = (
+ state = initialEndpointListState,
action
) => {
- if (action.type === 'serverReturnedHostList') {
+ if (action.type === 'serverReturnedEndpointList') {
const {
hosts,
total,
@@ -53,13 +53,13 @@ export const hostListReducer: ImmutableReducer = (
loading: false,
error: undefined,
};
- } else if (action.type === 'serverFailedToReturnHostList') {
+ } else if (action.type === 'serverFailedToReturnEndpointList') {
return {
...state,
error: action.payload,
loading: false,
};
- } else if (action.type === 'serverReturnedHostNonExistingPolicies') {
+ } else if (action.type === 'serverReturnedEndpointNonExistingPolicies') {
return {
...state,
nonExistingPolicies: {
@@ -67,14 +67,14 @@ export const hostListReducer: ImmutableReducer = (
...action.payload,
},
};
- } else if (action.type === 'serverReturnedHostDetails') {
+ } else if (action.type === 'serverReturnedEndpointDetails') {
return {
...state,
details: action.payload.metadata,
detailsLoading: false,
detailsError: undefined,
};
- } else if (action.type === 'serverFailedToReturnHostDetails') {
+ } else if (action.type === 'serverFailedToReturnEndpointDetails') {
return {
...state,
detailsError: action.payload,
@@ -92,14 +92,14 @@ export const hostListReducer: ImmutableReducer = (
error: action.payload,
policyItemsLoading: false,
};
- } else if (action.type === 'serverReturnedHostPolicyResponse') {
+ } else if (action.type === 'serverReturnedEndpointPolicyResponse') {
return {
...state,
policyResponse: action.payload.policy_response,
policyResponseLoading: false,
policyResponseError: undefined,
};
- } else if (action.type === 'serverFailedToReturnHostPolicyResponse') {
+ } else if (action.type === 'serverFailedToReturnEndpointPolicyResponse') {
return {
...state,
policyResponseError: action.payload,
@@ -111,7 +111,7 @@ export const hostListReducer: ImmutableReducer = (
selectedPolicyId: action.payload.selectedPolicyId,
policyResponseLoading: false,
};
- } else if (action.type === 'serverCancelledHostListLoading') {
+ } else if (action.type === 'serverCancelledEndpointListLoading') {
return {
...state,
loading: false,
@@ -126,22 +126,22 @@ export const hostListReducer: ImmutableReducer = (
...state,
endpointPackageInfo: action.payload,
};
- } else if (action.type === 'serverReturnedHostExistValue') {
+ } else if (action.type === 'serverReturnedEndpointExistValue') {
return {
...state,
- hostsExist: action.payload,
+ endpointsExist: action.payload,
};
} else if (action.type === 'userChangedUrl') {
- const newState: Immutable = {
+ const newState: Immutable = {
...state,
location: action.payload,
};
- const isCurrentlyOnListPage = isOnHostPage(newState) && !hasSelectedHost(newState);
- const wasPreviouslyOnListPage = isOnHostPage(state) && !hasSelectedHost(state);
- const isCurrentlyOnDetailsPage = isOnHostPage(newState) && hasSelectedHost(newState);
- const wasPreviouslyOnDetailsPage = isOnHostPage(state) && hasSelectedHost(state);
+ const isCurrentlyOnListPage = isOnEndpointPage(newState) && !hasSelectedEndpoint(newState);
+ const wasPreviouslyOnListPage = isOnEndpointPage(state) && !hasSelectedEndpoint(state);
+ const isCurrentlyOnDetailsPage = isOnEndpointPage(newState) && hasSelectedEndpoint(newState);
+ const wasPreviouslyOnDetailsPage = isOnEndpointPage(state) && hasSelectedEndpoint(state);
- // if on the host list page for the first time, return new location and load list
+ // if on the endpoint list page for the first time, return new location and load list
if (isCurrentlyOnListPage) {
if (!wasPreviouslyOnListPage) {
return {
@@ -154,7 +154,7 @@ export const hostListReducer: ImmutableReducer = (
};
}
} else if (isCurrentlyOnDetailsPage) {
- // if previous page was the list or another host details page, load host details only
+ // if previous page was the list or another endpoint details page, load endpoint details only
if (wasPreviouslyOnDetailsPage || wasPreviouslyOnListPage) {
return {
...state,
@@ -166,7 +166,7 @@ export const hostListReducer: ImmutableReducer = (
policyResponseError: undefined,
};
} else {
- // if previous page was not host list or host details, load both list and details
+ // if previous page was not endpoint list or endpoint details, load both list and details
return {
...state,
location: action.payload,
@@ -180,14 +180,14 @@ export const hostListReducer: ImmutableReducer = (
};
}
}
- // otherwise we are not on a host list or details page
+ // otherwise we are not on a endpoint list or details page
return {
...state,
location: action.payload,
error: undefined,
detailsError: undefined,
policyResponseError: undefined,
- hostsExist: true,
+ endpointsExist: true,
};
}
return state;
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts
index ca006f21c29ac..2c6fc6d5a75e1 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts
@@ -14,36 +14,36 @@ import {
HostPolicyResponseConfiguration,
HostPolicyResponseActionStatus,
} from '../../../../../common/endpoint/types';
-import { HostState, HostIndexUIQueryParams } from '../types';
-import { MANAGEMENT_ROUTING_HOSTS_PATH } from '../../../common/constants';
+import { EndpointState, EndpointIndexUIQueryParams } from '../types';
+import { MANAGEMENT_ROUTING_ENDPOINTS_PATH } from '../../../common/constants';
const PAGE_SIZES = Object.freeze([10, 20, 50]);
-export const listData = (state: Immutable) => state.hosts;
+export const listData = (state: Immutable