[ML] Convert anomalies controls to EUI / React (#19856)
* [ML] Convert anomalies controls to EUI / React * [ML] Edits to anomaly controls following review
This commit is contained in:
parent
2ada1b348a
commit
9d1ec94fac
|
@ -1,4 +0,0 @@
|
|||
<div ng-show="visible" class="ml-table-controls-element">
|
||||
<input id="ml-anomalies-controls-show-charts" type="checkbox" ng-model="showCharts" ng-change="toggleChartsVisibility()" />
|
||||
<label for="ml-anomalies-controls-show-charts" class="kuiLabel">Show Charts</label>
|
||||
</div>
|
|
@ -7,37 +7,49 @@
|
|||
|
||||
|
||||
/*
|
||||
* AngularJS directive+service for a checkbox element to toggle charts display.
|
||||
* React component for a checkbox element to toggle charts display.
|
||||
*/
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
import {
|
||||
EuiCheckbox
|
||||
} from '@elastic/eui';
|
||||
|
||||
import template from './checkbox_showcharts.html';
|
||||
import 'plugins/ml/components/controls/controls_select';
|
||||
import makeId from '@elastic/eui/lib/components/form/form_row/make_id';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
class CheckboxShowCharts extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
module
|
||||
.service('mlCheckboxShowChartsService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlCheckboxShowCharts', {
|
||||
showCharts: true
|
||||
});
|
||||
})
|
||||
.directive('mlCheckboxShowCharts', function (mlCheckboxShowChartsService) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template,
|
||||
scope: {
|
||||
visible: '='
|
||||
},
|
||||
link: function (scope) {
|
||||
scope.showCharts = mlCheckboxShowChartsService.state.get('showCharts');
|
||||
scope.toggleChartsVisibility = function () {
|
||||
mlCheckboxShowChartsService.state.set('showCharts', scope.showCharts);
|
||||
mlCheckboxShowChartsService.state.changed();
|
||||
};
|
||||
}
|
||||
// Restore the checked setting from the state.
|
||||
this.mlCheckboxShowChartsService = this.props.mlCheckboxShowChartsService;
|
||||
const showCharts = this.mlCheckboxShowChartsService.state.get('showCharts');
|
||||
|
||||
this.state = {
|
||||
checked: showCharts
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onChange = (e) => {
|
||||
const showCharts = e.target.checked;
|
||||
this.mlCheckboxShowChartsService.state.set('showCharts', showCharts);
|
||||
this.mlCheckboxShowChartsService.state.changed();
|
||||
|
||||
this.setState({
|
||||
checked: showCharts,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiCheckbox
|
||||
id={makeId()}
|
||||
label="Show charts"
|
||||
checked={this.state.checked}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { CheckboxShowCharts };
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import 'ngreact';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { CheckboxShowCharts } from './checkbox_showcharts';
|
||||
|
||||
module.service('mlCheckboxShowChartsService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlCheckboxShowCharts', {
|
||||
showCharts: true
|
||||
});
|
||||
})
|
||||
.directive('mlCheckboxShowCharts', function ($injector) {
|
||||
const reactDirective = $injector.get('reactDirective');
|
||||
const mlCheckboxShowChartsService = $injector.get('mlCheckboxShowChartsService');
|
||||
|
||||
return reactDirective(
|
||||
CheckboxShowCharts,
|
||||
undefined,
|
||||
{ restrict: 'E' },
|
||||
{ mlCheckboxShowChartsService }
|
||||
);
|
||||
});
|
|
@ -5,5 +5,4 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
import './checkbox_showcharts';
|
||||
import './checkbox_showcharts_directive';
|
||||
|
|
|
@ -1,44 +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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from 'expect.js';
|
||||
|
||||
describe('ML - <ml-select-interval>', () => {
|
||||
let $scope;
|
||||
let $compile;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(() => {
|
||||
ngMock.inject(function ($injector) {
|
||||
$compile = $injector.get('$compile');
|
||||
const $rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
it('Initialization doesn\'t throw an error', () => {
|
||||
expect(function () {
|
||||
$compile('<ml-select-interval />')($scope);
|
||||
}).to.not.throwError('Not initialized.');
|
||||
|
||||
expect($scope.setInterval).to.be.a('function');
|
||||
expect($scope.interval).to.eql({ display: 'Auto', val: 'auto' });
|
||||
expect($scope.intervalOptions).to.eql([
|
||||
{ display: 'Auto', val: 'auto' },
|
||||
{ display: '1 hour', val: 'hour' },
|
||||
{ display: '1 day', val: 'day' },
|
||||
{ display: 'Show all', val: 'second' }
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
|
@ -5,5 +5,4 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
import './select_interval.js';
|
||||
import './select_interval_directive';
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<ml-controls-select
|
||||
identifier="Interval"
|
||||
label="Interval"
|
||||
options="intervalOptions"
|
||||
selected="interval"
|
||||
show-icons="false"
|
||||
update-fn="setInterval"
|
||||
/>
|
|
@ -7,65 +7,72 @@
|
|||
|
||||
|
||||
/*
|
||||
* AngularJS directive for rendering a select element with various interval levels.
|
||||
* React component for rendering a select element with various aggregation interval levels.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
import {
|
||||
EuiSelect
|
||||
} from '@elastic/eui';
|
||||
|
||||
import template from './select_interval.html';
|
||||
import 'plugins/ml/components/controls/controls_select';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
const OPTIONS = [
|
||||
{ value: 'auto', text: 'Auto' },
|
||||
{ value: 'hour', text: '1 hour' },
|
||||
{ value: 'day', text: '1 day' },
|
||||
{ value: 'second', text: 'Show all' }
|
||||
];
|
||||
|
||||
module
|
||||
.service('mlSelectIntervalService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlSelectInterval', {
|
||||
interval: { display: 'Auto', val: 'auto' }
|
||||
});
|
||||
})
|
||||
.directive('mlSelectInterval', function (mlSelectIntervalService) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template,
|
||||
link: function (scope, element) {
|
||||
scope.intervalOptions = [
|
||||
{ display: 'Auto', val: 'auto' },
|
||||
{ display: '1 hour', val: 'hour' },
|
||||
{ display: '1 day', val: 'day' },
|
||||
{ display: 'Show all', val: 'second' }
|
||||
];
|
||||
function optionValueToInterval(value) {
|
||||
// Builds the corresponding interval object with the required display and val properties
|
||||
// from the specified value.
|
||||
const option = OPTIONS.find(opt => (opt.value === value));
|
||||
|
||||
const intervalState = mlSelectIntervalService.state.get('interval');
|
||||
const intervalValue = _.get(intervalState, 'val', 'auto');
|
||||
let intervalOption = scope.intervalOptions.find(d => d.val === intervalValue);
|
||||
if (intervalOption === undefined) {
|
||||
// Attempt to set value in URL which doesn't map to one of the options.
|
||||
intervalOption = scope.intervalOptions.find(d => d.val === 'auto');
|
||||
}
|
||||
scope.interval = intervalOption;
|
||||
mlSelectIntervalService.state.set('interval', scope.interval);
|
||||
// Default to auto if supplied value doesn't map to one of the options.
|
||||
let interval = OPTIONS[0];
|
||||
if (option !== undefined) {
|
||||
interval = { display: option.text, val: option.value };
|
||||
}
|
||||
|
||||
scope.setInterval = function (interval) {
|
||||
if (!_.isEqual(scope.interval, interval)) {
|
||||
scope.interval = interval;
|
||||
mlSelectIntervalService.state.set('interval', scope.interval).changed();
|
||||
}
|
||||
};
|
||||
return interval;
|
||||
}
|
||||
|
||||
function setScopeInterval() {
|
||||
scope.setInterval(mlSelectIntervalService.state.get('interval'));
|
||||
}
|
||||
class SelectInterval extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
mlSelectIntervalService.state.watch(setScopeInterval);
|
||||
// Restore the interval from the state, or default to auto.
|
||||
this.mlSelectIntervalService = this.props.mlSelectIntervalService;
|
||||
const intervalState = this.mlSelectIntervalService.state.get('interval');
|
||||
const intervalValue = _.get(intervalState, 'val', 'auto');
|
||||
const interval = optionValueToInterval(intervalValue);
|
||||
this.mlSelectIntervalService.state.set('interval', interval);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
mlSelectIntervalService.state.unwatch(setScopeInterval);
|
||||
scope.$destroy();
|
||||
});
|
||||
}
|
||||
this.state = {
|
||||
value: interval.val
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onChange = (e) => {
|
||||
this.setState({
|
||||
value: e.target.value,
|
||||
});
|
||||
|
||||
const interval = optionValueToInterval(e.target.value);
|
||||
this.mlSelectIntervalService.state.set('interval', interval).changed();
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiSelect
|
||||
options={OPTIONS}
|
||||
className="ml-select-interval"
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { SelectInterval };
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import 'ngreact';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { SelectInterval } from './select_interval';
|
||||
|
||||
module.service('mlSelectIntervalService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlSelectInterval', {
|
||||
interval: { display: 'Auto', val: 'auto' }
|
||||
});
|
||||
})
|
||||
.directive('mlSelectInterval', function ($injector) {
|
||||
const reactDirective = $injector.get('reactDirective');
|
||||
const mlSelectIntervalService = $injector.get('mlSelectIntervalService');
|
||||
|
||||
return reactDirective(
|
||||
SelectInterval,
|
||||
undefined,
|
||||
{ restrict: 'E' },
|
||||
{ mlSelectIntervalService }
|
||||
);
|
||||
});
|
|
@ -1,44 +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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from 'expect.js';
|
||||
|
||||
describe('ML - <ml-select-severity>', () => {
|
||||
let $scope;
|
||||
let $compile;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(() => {
|
||||
ngMock.inject(function ($injector) {
|
||||
$compile = $injector.get('$compile');
|
||||
const $rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
it('Initialization doesn\'t throw an error', () => {
|
||||
expect(function () {
|
||||
$compile('<ml-select-severity />')($scope);
|
||||
}).to.not.throwError('Not initialized.');
|
||||
|
||||
expect($scope.setThreshold).to.be.a('function');
|
||||
expect($scope.threshold).to.eql({ display: 'warning', val: 0 });
|
||||
expect($scope.thresholdOptions).to.eql([
|
||||
{ display: 'critical', val: 75 },
|
||||
{ display: 'major', val: 50 },
|
||||
{ display: 'minor', val: 25 },
|
||||
{ display: 'warning', val: 0 }
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
|
@ -5,5 +5,5 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
import './select_severity.js';
|
||||
import './select_severity_directive';
|
||||
import './styles/main.less';
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<ml-controls-select
|
||||
identifier="Severity"
|
||||
label="Severity threshold"
|
||||
options="thresholdOptions"
|
||||
selected="threshold"
|
||||
show-icons="true"
|
||||
update-fn="setThreshold"
|
||||
/>
|
|
@ -7,65 +7,101 @@
|
|||
|
||||
|
||||
/*
|
||||
* AngularJS directive for rendering a select element with threshold levels.
|
||||
*/
|
||||
|
||||
* React component for rendering a select element with threshold levels.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
import {
|
||||
EuiComboBox,
|
||||
EuiHighlight,
|
||||
EuiHealth,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import template from './select_severity.html';
|
||||
import 'plugins/ml/components/controls/controls_select';
|
||||
import { getSeverityColor } from 'plugins/ml/../common/util/anomaly_utils';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
const OPTIONS = [
|
||||
{ value: 0, label: 'warning', color: getSeverityColor(0) },
|
||||
{ value: 25, label: 'minor', color: getSeverityColor(25) },
|
||||
{ value: 50, label: 'major', color: getSeverityColor(50) },
|
||||
{ value: 75, label: 'critical', color: getSeverityColor(75) }
|
||||
];
|
||||
|
||||
module
|
||||
.service('mlSelectSeverityService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlSelectSeverity', {
|
||||
threshold: { display: 'warning', val: 0 }
|
||||
});
|
||||
})
|
||||
.directive('mlSelectSeverity', function (mlSelectSeverityService) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template,
|
||||
link: function (scope, element) {
|
||||
scope.thresholdOptions = [
|
||||
{ display: 'critical', val: 75 },
|
||||
{ display: 'major', val: 50 },
|
||||
{ display: 'minor', val: 25 },
|
||||
{ display: 'warning', val: 0 }
|
||||
];
|
||||
function optionValueToThreshold(value) {
|
||||
// Builds the corresponding threshold object with the required display and val properties
|
||||
// from the specified value.
|
||||
const option = OPTIONS.find(opt => (opt.value === value));
|
||||
|
||||
const thresholdState = mlSelectSeverityService.state.get('threshold');
|
||||
const thresholdValue = _.get(thresholdState, 'val', 0);
|
||||
let thresholdOption = scope.thresholdOptions.find(d => d.val === thresholdValue);
|
||||
if (thresholdOption === undefined) {
|
||||
// Attempt to set value in URL which doesn't map to one of the options.
|
||||
thresholdOption = scope.thresholdOptions.find(d => d.val === 0);
|
||||
}
|
||||
scope.threshold = thresholdOption;
|
||||
mlSelectSeverityService.state.set('threshold', scope.threshold);
|
||||
// Default to warning if supplied value doesn't map to one of the options.
|
||||
let threshold = OPTIONS[0];
|
||||
if (option !== undefined) {
|
||||
threshold = { display: option.label, val: option.value };
|
||||
}
|
||||
|
||||
scope.setThreshold = function (threshold) {
|
||||
if(!_.isEqual(scope.threshold, threshold)) {
|
||||
scope.threshold = threshold;
|
||||
mlSelectSeverityService.state.set('threshold', scope.threshold).changed();
|
||||
}
|
||||
};
|
||||
return threshold;
|
||||
}
|
||||
|
||||
function setThreshold() {
|
||||
scope.setThreshold(mlSelectSeverityService.state.get('threshold'));
|
||||
}
|
||||
class SelectSeverity extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
mlSelectSeverityService.state.watch(setThreshold);
|
||||
// Restore the threshold from the state, or default to warning.
|
||||
this.mlSelectSeverityService = this.props.mlSelectSeverityService;
|
||||
const thresholdState = this.mlSelectSeverityService.state.get('threshold');
|
||||
const thresholdValue = _.get(thresholdState, 'val', 0);
|
||||
const threshold = optionValueToThreshold(thresholdValue);
|
||||
const selectedOption = OPTIONS.find(opt => (opt.value === threshold.val));
|
||||
|
||||
element.on('$destroy', () => {
|
||||
mlSelectSeverityService.state.unwatch(setThreshold);
|
||||
scope.$destroy();
|
||||
});
|
||||
}
|
||||
this.mlSelectSeverityService.state.set('threshold', threshold);
|
||||
|
||||
this.state = {
|
||||
selectedOptions: [selectedOption]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onChange = (selectedOptions) => {
|
||||
if (selectedOptions.length === 0) {
|
||||
// Don't allow no options to be selected.
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
selectedOptions,
|
||||
});
|
||||
|
||||
const threshold = optionValueToThreshold(selectedOptions[0].value);
|
||||
this.mlSelectSeverityService.state.set('threshold', threshold).changed();
|
||||
};
|
||||
|
||||
renderOption = (option, searchValue, contentClassName) => {
|
||||
const { color, label, value } = option;
|
||||
return (
|
||||
<EuiHealth color={color}>
|
||||
<span className={contentClassName}>
|
||||
<EuiHighlight search={searchValue}>
|
||||
{label}
|
||||
</EuiHighlight>
|
||||
|
||||
<span>({value})</span>
|
||||
</span>
|
||||
</EuiHealth>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { selectedOptions } = this.state;
|
||||
return (
|
||||
<EuiComboBox
|
||||
placeholder="Select severity"
|
||||
className="ml-select-severity"
|
||||
singleSelection={true}
|
||||
options={OPTIONS}
|
||||
selectedOptions={selectedOptions}
|
||||
onChange={this.onChange}
|
||||
renderOption={this.renderOption}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { SelectSeverity };
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import 'ngreact';
|
||||
|
||||
import { stateFactoryProvider } from 'plugins/ml/factories/state_factory';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { SelectSeverity } from './select_severity';
|
||||
|
||||
module.service('mlSelectSeverityService', function (Private) {
|
||||
const stateFactory = Private(stateFactoryProvider);
|
||||
this.state = stateFactory('mlSelectSeverity', {
|
||||
threshold: { display: 'warning', val: 0 }
|
||||
});
|
||||
})
|
||||
.directive('mlSelectSeverity', function ($injector) {
|
||||
const reactDirective = $injector.get('reactDirective');
|
||||
const mlSelectSeverityService = $injector.get('mlSelectSeverityService');
|
||||
|
||||
return reactDirective(
|
||||
SelectSeverity,
|
||||
undefined,
|
||||
{ restrict: 'E' },
|
||||
{ mlSelectSeverityService }
|
||||
);
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
.ml-select-severity {
|
||||
.euiFormControlLayoutClearButton {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ describe('ML - Explorer Controller', () => {
|
|||
const scope = $rootScope.$new();
|
||||
$controller('MlExplorerController', { $scope: scope });
|
||||
|
||||
expect(scope.showCharts).to.be.true;
|
||||
expect(scope.loading).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -119,12 +119,30 @@
|
|||
Anomalies
|
||||
</span>
|
||||
|
||||
<div class="ml-table-controls">
|
||||
<ml-select-severity />
|
||||
<ml-select-interval />
|
||||
<ml-checkbox-show-charts
|
||||
visible="anomalyChartRecords.length > 0"
|
||||
/>
|
||||
<div class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive ml-anomalies-controls">
|
||||
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
|
||||
<div class="euiFormRow" id="select_severity_control">
|
||||
<label class="euiFormLabel" for="select_severity">Severity threshold</label>
|
||||
<div class="euiFormControlLayout">
|
||||
<ml-select-severity id="select_severity" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
|
||||
<div class="euiFormRow" id="select_interval_control">
|
||||
<label class="euiFormLabel" for="select_interval">Interval</label>
|
||||
<div class="euiFormControlLayout">
|
||||
<ml-select-interval id="select_interval" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="euiFlexItem euiFlexItem--flexGrowZero" ng-show="anomalyChartRecords.length > 0">
|
||||
<div class="euiFormRow" id="show_charts_checkbox_control">
|
||||
<div class="euiFormControlLayout">
|
||||
<ml-checkbox-show-charts id="show_charts_checkbox" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-controller="MlExplorerChartsContainerController" class="euiText">
|
||||
|
@ -141,7 +159,6 @@
|
|||
</ml-explorer-charts-container>
|
||||
</div>
|
||||
|
||||
|
||||
<ml-anomalies-table
|
||||
table-data="tableData"
|
||||
/>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<span ng-if="series.entityFields.length > 0">{{series.detectorLabel}} - </span>
|
||||
<span ng-if="series.entityFields.length === 0">{{series.detectorLabel}}</span>
|
||||
<span ng-repeat='entity in series.entityFields'>
|
||||
{{entity.fieldName}} {{entity.fieldValue}} {{entity.fieldValueTest}}
|
||||
{{entity.fieldName}} {{entity.fieldValue}}
|
||||
</span>
|
||||
</div>
|
||||
<i aria-hidden="true" class="fa fa-info-circle" tooltip-placement="left" tooltip-html-unsafe="{{series.infoTooltip}}" tooltip-append-to-body="false"></i>
|
||||
|
|
|
@ -113,6 +113,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ml-anomalies-controls {
|
||||
padding-top: 5px;
|
||||
|
||||
#show_charts_checkbox_control {
|
||||
padding-top: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.ml-explorer-swimlane {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
|
|
|
@ -81,6 +81,10 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
.ml-anomalies-controls {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.ml-timeseries-chart {
|
||||
svg {
|
||||
font-size: 12px;
|
||||
|
|
|
@ -121,9 +121,23 @@
|
|||
Anomalies
|
||||
</span>
|
||||
|
||||
<div class="ml-table-controls">
|
||||
<ml-select-severity />
|
||||
<ml-select-interval />
|
||||
<div class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive ml-anomalies-controls">
|
||||
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
|
||||
<div class="euiFormRow" id="select_severity_control">
|
||||
<label class="euiFormLabel" for="select_severity">Severity threshold</label>
|
||||
<div class="euiFormControlLayout">
|
||||
<ml-select-severity id="select_severity" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="euiFlexItem euiFlexItem--flexGrowZero" style="width:170px">
|
||||
<div class="euiFormRow" id="select_interval_control">
|
||||
<label class="euiFormLabel" for="select_interval">Interval</label>
|
||||
<div class="euiFormControlLayout">
|
||||
<ml-select-interval id="select_interval" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ml-anomalies-table
|
||||
|
|
Loading…
Reference in a new issue