mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[i18n] Translate ML - New Job - components (#27587)
* Translate new_job -> components * Resolve review comments * Update snapshot
This commit is contained in:
parent
5f7c9c077f
commit
3faff023c8
23 changed files with 333 additions and 107 deletions
|
@ -5,7 +5,13 @@ exports[`BucketSpanEstimator renders the button 1`] = `
|
|||
className="bucket-span-estimator"
|
||||
>
|
||||
<EuiToolTip
|
||||
content="Experimental feature for estimating bucket span."
|
||||
content={
|
||||
<FormattedMessage
|
||||
defaultMessage="Experimental feature for estimating bucket span."
|
||||
id="xpack.ml.newJob.simple.bucketSpanEstimator.estimateBucketSpanButtonTooltip"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
delay="regular"
|
||||
position="bottom"
|
||||
>
|
||||
|
@ -30,7 +36,13 @@ exports[`BucketSpanEstimator renders the loading button 1`] = `
|
|||
className="bucket-span-estimator"
|
||||
>
|
||||
<EuiToolTip
|
||||
content="Experimental feature for estimating bucket span."
|
||||
content={
|
||||
<FormattedMessage
|
||||
defaultMessage="Experimental feature for estimating bucket span."
|
||||
id="xpack.ml.newJob.simple.bucketSpanEstimator.estimateBucketSpanButtonTooltip"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
delay="regular"
|
||||
position="bottom"
|
||||
>
|
||||
|
|
|
@ -11,10 +11,12 @@ import { BucketSpanEstimator } from './bucket_span_estimator_view';
|
|||
import { EVENT_RATE_COUNT_FIELD } from 'plugins/ml/jobs/new_job/simple/components/constants/general';
|
||||
import { ml } from 'plugins/ml/services/ml_api_service';
|
||||
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
|
||||
module.directive('mlBucketSpanEstimator', function () {
|
||||
module.directive('mlBucketSpanEstimator', function (i18n) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: false,
|
||||
|
@ -115,7 +117,13 @@ module.directive('mlBucketSpanEstimator', function () {
|
|||
$scope.ui.bucketSpanEstimator.status === STATUS.RUNNING
|
||||
);
|
||||
const estimatorRunning = ($scope.ui.bucketSpanEstimator.status === STATUS.RUNNING);
|
||||
const buttonText = (estimatorRunning) ? 'Estimating bucket span' : 'Estimate bucket span';
|
||||
const buttonText = (estimatorRunning)
|
||||
? i18n('xpack.ml.newJob.simple.bucketSpanEstimator.estimatingBucketSpanButtonLabel', {
|
||||
defaultMessage: 'Estimating bucket span'
|
||||
})
|
||||
: i18n('xpack.ml.newJob.simple.bucketSpanEstimator.estimateBucketSpanButtonLabel', {
|
||||
defaultMessage: 'Estimate bucket span'
|
||||
});
|
||||
|
||||
const props = {
|
||||
buttonDisabled,
|
||||
|
@ -125,7 +133,9 @@ module.directive('mlBucketSpanEstimator', function () {
|
|||
};
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement(BucketSpanEstimator, props),
|
||||
<I18nProvider>
|
||||
{React.createElement(BucketSpanEstimator, props)}
|
||||
</I18nProvider>,
|
||||
$element[0]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,12 +11,16 @@ import {
|
|||
EuiButton,
|
||||
EuiToolTip
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function BucketSpanEstimator({ buttonDisabled, buttonText, estimatorRunning, guessBucketSpan }) {
|
||||
return (
|
||||
<div className="bucket-span-estimator">
|
||||
<EuiToolTip
|
||||
content="Experimental feature for estimating bucket span."
|
||||
content={<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.bucketSpanEstimator.estimateBucketSpanButtonTooltip"
|
||||
defaultMessage="Experimental feature for estimating bucket span."
|
||||
/>}
|
||||
position="bottom"
|
||||
>
|
||||
<EuiButton
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import React from 'react';
|
||||
|
||||
import { BucketSpanEstimator } from './bucket_span_estimator_view';
|
||||
|
@ -18,7 +18,7 @@ describe('BucketSpanEstimator', () => {
|
|||
guessBucketSpan: () => { },
|
||||
buttonText: 'Estimate bucket span'
|
||||
};
|
||||
const wrapper = shallow(<BucketSpanEstimator {...props} />);
|
||||
const wrapper = shallowWithIntl(<BucketSpanEstimator {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -29,7 +29,7 @@ describe('BucketSpanEstimator', () => {
|
|||
guessBucketSpan: () => { },
|
||||
buttonText: 'Estimating bucket span'
|
||||
};
|
||||
const wrapper = shallow(<BucketSpanEstimator {...props} />);
|
||||
const wrapper = shallowWithIntl(<BucketSpanEstimator {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<div class='bucket-span-selection'>
|
||||
<h4 class="euiTitle euiTitle--small" id="ml_aria_label_new_job_bucketspan">Bucket span</h4><i ml-info-icon="new_job_bucketspan" />
|
||||
<h4
|
||||
class="euiTitle euiTitle--small"
|
||||
id="ml_aria_label_new_job_bucketspan"
|
||||
i18n-id="xpack.ml.newJob.simple.bucketSpanSelection.bucketSpanTitle"
|
||||
i18n-default-message="Bucket span"
|
||||
></h4><i ml-info-icon="new_job_bucketspan" />
|
||||
<div class="euiSpacer euiSpacer--s"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -26,7 +31,12 @@
|
|||
</ml-bucket-span-estimator>
|
||||
|
||||
</div>
|
||||
<div ng-hide="ui.bucketSpanValid" class="validation-error">Invalid interval format</div>
|
||||
<div
|
||||
ng-hide="ui.bucketSpanValid"
|
||||
class="validation-error"
|
||||
i18n-id="xpack.ml.newJob.simple.bucketSpanSelection.invalidIntervalFormatLabel"
|
||||
i18n-default-message="Invalid interval format"
|
||||
></div>
|
||||
<div ng-show="ui.bucketSpanEstimator.status===-1" class="validation-error">{{ui.bucketSpanEstimator.message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { EnableModelPlotCheckbox } from './enable_model_plot_checkbox_view.js';
|
||||
|
||||
const defaultProps = {
|
||||
|
@ -18,7 +18,7 @@ const defaultProps = {
|
|||
describe('EnableModelPlotCheckbox', () => {
|
||||
|
||||
test('checkbox default is rendered correctly', () => {
|
||||
const wrapper = mount(<EnableModelPlotCheckbox {...defaultProps} />);
|
||||
const wrapper = mountWithIntl(<EnableModelPlotCheckbox {...defaultProps} />);
|
||||
const checkbox = wrapper.find({ type: 'checkbox' });
|
||||
const label = wrapper.find('label');
|
||||
|
||||
|
@ -30,7 +30,7 @@ describe('EnableModelPlotCheckbox', () => {
|
|||
const mockOnChange = jest.fn();
|
||||
defaultProps.onCheckboxChange = mockOnChange;
|
||||
|
||||
const wrapper = mount(<EnableModelPlotCheckbox {...defaultProps} />);
|
||||
const wrapper = mountWithIntl(<EnableModelPlotCheckbox {...defaultProps} />);
|
||||
const checkbox = wrapper.find({ type: 'checkbox' });
|
||||
|
||||
checkbox.simulate('change', { target: { checked: true } });
|
||||
|
|
|
@ -11,10 +11,12 @@ import { EnableModelPlotCheckbox } from './enable_model_plot_checkbox_view.js';
|
|||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { checkCardinalitySuccess } from '../../../utils/new_job_utils';
|
||||
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
|
||||
module.directive('mlEnableModelPlotCheckbox', function () {
|
||||
module.directive('mlEnableModelPlotCheckbox', function (i18n) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: false,
|
||||
|
@ -35,10 +37,12 @@ module.directive('mlEnableModelPlotCheckbox', function () {
|
|||
function errorHandler(error) {
|
||||
console.log('Cardinality could not be validated', error);
|
||||
$scope.ui.cardinalityValidator.status = STATUS.FAILED;
|
||||
$scope.ui.cardinalityValidator.message = `An error occurred validating the configuration
|
||||
for running the job with model plot enabled.
|
||||
Creating model plots can be resource intensive and not recommended where the cardinality of the selected fields is high.
|
||||
You may want to select a dedicated results index on the Job Details tab.`;
|
||||
$scope.ui.cardinalityValidator.message = i18n('xpack.ml.newJob.simple.enableModelPlot.validatingConfigurationErrorMessage', {
|
||||
defaultMessage: 'An error occurred validating the configuration' +
|
||||
'for running the job with model plot enabled.' +
|
||||
'Creating model plots can be resource intensive and not recommended where the cardinality of the selected fields is high.' +
|
||||
'You may want to select a dedicated results index on the Job Details tab.'
|
||||
});
|
||||
// Go ahead and check the dedicated index box for them
|
||||
$scope.formConfig.useDedicatedIndex = true;
|
||||
}
|
||||
|
@ -57,11 +61,14 @@ module.directive('mlEnableModelPlotCheckbox', function () {
|
|||
if (validationResult.success === true) {
|
||||
$scope.formConfig.enableModelPlot = true;
|
||||
$scope.ui.cardinalityValidator.status = STATUS.FINISHED;
|
||||
} else {
|
||||
$scope.ui.cardinalityValidator.message = `Creating model plots is resource intensive and not recommended
|
||||
where the cardinality of the selected fields is greater than 100. Estimated cardinality
|
||||
for this job is ${validationResult.highCardinality}.
|
||||
If you enable model plot with this configuration we recommend you use a dedicated results index.`;
|
||||
|
||||
$scope.ui.cardinalityValidator.message = i18n('xpack.ml.newJob.simple.enableModelPlot.enableModelPlotDescription', {
|
||||
defaultMessage: 'Creating model plots is resource intensive and not recommended' +
|
||||
'where the cardinality of the selected fields is greater than 100. Estimated cardinality' +
|
||||
'for this job is {highCardinality}.' +
|
||||
'If you enable model plot with this configuration we recommend you use a dedicated results index.',
|
||||
values: { highCardinality: validationResult.highCardinality }
|
||||
});
|
||||
|
||||
$scope.ui.cardinalityValidator.status = STATUS.WARNING;
|
||||
// Go ahead and check the dedicated index box for them
|
||||
|
@ -115,7 +122,13 @@ module.directive('mlEnableModelPlotCheckbox', function () {
|
|||
($scope.ui.cardinalityValidator.status === STATUS.WARNING ||
|
||||
$scope.ui.cardinalityValidator.status === STATUS.FAILED) &&
|
||||
$scope.ui.formValid === true);
|
||||
const checkboxText = (validatorRunning) ? 'Validating cardinality...' : 'Enable model plot';
|
||||
const checkboxText = (validatorRunning)
|
||||
? i18n('xpack.ml.newJob.simple.enableModelPlot.validatingCardinalityLabel', {
|
||||
defaultMessage: 'Validating cardinality…'
|
||||
})
|
||||
: i18n('xpack.ml.newJob.simple.enableModelPlot.enableModelPlotLabel', {
|
||||
defaultMessage: 'Enable model plot'
|
||||
});
|
||||
|
||||
const props = {
|
||||
checkboxDisabled,
|
||||
|
@ -126,7 +139,9 @@ module.directive('mlEnableModelPlotCheckbox', function () {
|
|||
};
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement(EnableModelPlotCheckbox, props),
|
||||
<I18nProvider>
|
||||
{React.createElement(EnableModelPlotCheckbox, props)}
|
||||
</I18nProvider>,
|
||||
$element[0]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
|
||||
import { JsonTooltip } from '../../../../../components/json_tooltip/json_tooltip';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export class EnableModelPlotCheckbox extends Component {
|
||||
constructor(props) {
|
||||
|
@ -28,7 +29,10 @@ export class EnableModelPlotCheckbox extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
warningTitle = 'Proceed with caution!';
|
||||
warningTitle = (<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.enableModelPlot.proceedWithCautionWarningTitle"
|
||||
defaultMessage="Proceed with caution!"
|
||||
/>);
|
||||
|
||||
onChange = (e) => {
|
||||
this.setState({
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<div class='fields-selection'>
|
||||
<h4 class="euiTitle euiTitle--small">Fields</h4>
|
||||
<h4
|
||||
class="euiTitle euiTitle--small"
|
||||
i18n-id="xpack.ml.newJob.simple.fieldsSelection.fieldsTitle"
|
||||
i18n-default-message="Fields"
|
||||
></h4>
|
||||
<div class="euiSpacer euiSpacer--s"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -43,7 +47,11 @@
|
|||
ng-disabled="ui.formValid === false || jobState === JOB_STATE.RUNNING || jobState === JOB_STATE.STOPPING || jobState === JOB_STATE.FINISHED"
|
||||
ng-model ="formConfig.isSparseData" />
|
||||
<span class='kuiCheckBoxLabel__text'>
|
||||
Sparse data <i ml-info-icon="new_job_sparsedata" tooltip-append-to-body="true"></i>
|
||||
<span
|
||||
i18n-id="xpack.ml.newJob.simple.fieldsSelection.sparseDataLabel"
|
||||
i18n-default-message="Sparse data"
|
||||
></span>
|
||||
<i ml-info-icon="new_job_sparsedata" tooltip-append-to-body="true"></i>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<div class='fields-selection-population'>
|
||||
<h4 class="euiTitle euiTitle--small">Fields</h4>
|
||||
<h4
|
||||
class="euiTitle euiTitle--small"
|
||||
i18n-id="xpack.ml.newJob.simple.fieldsSelectionPopulation.fieldsTitle"
|
||||
i18n-default-message="Fields"
|
||||
></h4>
|
||||
<div class="euiSpacer euiSpacer--s"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -50,7 +54,7 @@
|
|||
</select>
|
||||
</div>
|
||||
<button
|
||||
aria-label="Remove Detector"
|
||||
aria-label="{{ ::'xpack.ml.newJob.simple.fieldsSelectionPopulation.removeDetectorButtonAriaLabel' | i18n: {defaultMessage: 'Remove Detector'} }}"
|
||||
ng-click="removeField($index, field)"
|
||||
tooltip-append-to-body="true"
|
||||
ng-disabled="formConfig.fields[$index] === undefined || jobState === JOB_STATE.RUNNING || jobState === JOB_STATE.STOPPING || jobState === JOB_STATE.FINISHED"
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
<div class="general-job-details">
|
||||
<div class="form-group">
|
||||
<ml-form-label label-id="new_job_id" tooltip-append-to-body="true">Name</ml-form-label>
|
||||
<ml-form-label label-id="new_job_id" tooltip-append-to-body="true">
|
||||
{{ ::'xpack.ml.newJob.simple.generalJobDetails.nameLabel' | i18n: {defaultMessage: 'Name'} }}
|
||||
</ml-form-label>
|
||||
<input
|
||||
aria-labelledby="ml_aria_label_new_job_id"
|
||||
aria-describedby="ml_aria_description_new_job_id"
|
||||
id="job-id-input"
|
||||
ng-model="formConfig.jobId"
|
||||
required
|
||||
placeholder="Job ID"
|
||||
placeholder="{{ ::'xpack.ml.newJob.simple.generalJobDetails.jobIdPlaceholder' | i18n: {defaultMessage: 'Job ID'} }}"
|
||||
ng-change="changeJobIDCase(formConfig)"
|
||||
ng-disabled="jobState === JOB_STATE.RUNNING || jobState === JOB_STATE.STOPPING || jobState === JOB_STATE.FINISHED"
|
||||
class="form-control lowercase" />
|
||||
|
@ -15,17 +17,21 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<ml-form-label label-id="new_job_description">Description</ml-form-label>
|
||||
<ml-form-label label-id="new_job_description">
|
||||
{{ ::'xpack.ml.newJob.simple.generalJobDetails.descriptionLabel' | i18n: {defaultMessage: 'Description'} }}
|
||||
</ml-form-label>
|
||||
<input
|
||||
aria-labelledby="ml_aria_label_new_job_description"
|
||||
aria-describedby="ml_aria_description_new_job_description"
|
||||
ng-model="formConfig.description"
|
||||
placeholder="Job description"
|
||||
placeholder="{{ ::'xpack.ml.newJob.simple.generalJobDetails.jobDescriptionPlaceholder' | i18n: {defaultMessage: 'Job description'} }}"
|
||||
ng-disabled="jobState === JOB_STATE.RUNNING || jobState === JOB_STATE.STOPPING || jobState === JOB_STATE.FINISHED"
|
||||
class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<ml-form-label label-id="new_job_group">Job Groups</ml-form-label>
|
||||
<ml-form-label label-id="new_job_group">
|
||||
{{ ::'xpack.ml.newJob.simple.generalJobDetails.jobGroupsLabel' | i18n: {defaultMessage: 'Job Groups'} }}
|
||||
</ml-form-label>
|
||||
<ml-job-group-select
|
||||
aria-labelledby="ml_aria_label_new_job_group"
|
||||
aria-describedby="ml_aria_description_new_job_group"
|
||||
|
@ -37,13 +43,18 @@
|
|||
<div class="form-group">
|
||||
<div ng-click="ui.showAdvanced = (!ui.showAdvanced || formConfig.useDedicatedIndex)" class="advanced-button-container">
|
||||
<button
|
||||
aria-label="{{ ui.showAdvanced ? 'Hide Advanced' : 'Show Advanced' }}"
|
||||
aria-label="{{ ui.showAdvanced ? hideAdvancedButtonAriaLabel : showAdvancedButtonAriaLabel }}"
|
||||
ng-disabled="formConfig.useDedicatedIndex"
|
||||
type="button"
|
||||
class="kuiButton kuiButton--small kuiButton--hollow advanced-button">
|
||||
<i aria-hidden="true" ng-class="{ 'fa-caret-down': ui.showAdvanced, 'fa-caret-right': !ui.showAdvanced }" class="fa"></i>
|
||||
</button>
|
||||
<label class="kuiFormLabel" aria-describedby="ml_aria_description_new_job_advanced_settings">Advanced</label>
|
||||
<label
|
||||
class="kuiFormLabel"
|
||||
aria-describedby="ml_aria_description_new_job_advanced_settings"
|
||||
i18n-id="xpack.ml.newJob.simple.generalJobDetails.advancedLabel"
|
||||
i18n-default-message="Advanced"
|
||||
></label>
|
||||
<i ml-info-icon="new_job_advanced_settings" ></i>
|
||||
</div>
|
||||
<div class='advanced-group' ng-show="ui.showAdvanced">
|
||||
|
@ -62,16 +73,22 @@
|
|||
class='kuiCheckBox'
|
||||
ng-model ="formConfig.useDedicatedIndex" />
|
||||
<span class='kuiCheckBoxLabel__text dedicated-index-label'>
|
||||
<span id="ml_aria_label_new_job_dedicated_index">Use dedicated index</span>
|
||||
<span
|
||||
id="ml_aria_label_new_job_dedicated_index"
|
||||
i18n-id="xpack.ml.newJob.simple.generalJobDetails.useDedicatedIndexLabel"
|
||||
i18n-default-message="Use dedicated index"
|
||||
></span>
|
||||
<i ml-info-icon="new_job_dedicated_index" ></i>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class='kuiFormLabel kuiVerticalRhythm'>
|
||||
<span id="ml_aria_label_new_job_model_memory_limit">
|
||||
Model memory limit
|
||||
</span>
|
||||
<span
|
||||
id="ml_aria_label_new_job_model_memory_limit"
|
||||
i18n-id="xpack.ml.newJob.simple.generalJobDetails.modelMemoryLimitLabel"
|
||||
i18n-default-message="Model memory limit"
|
||||
></span>
|
||||
<i ml-info-icon="new_job_model_memory_limit"></i>
|
||||
</label>
|
||||
<div></div>
|
||||
|
|
|
@ -17,9 +17,15 @@ module.directive('mlGeneralJobDetails', function () {
|
|||
restrict: 'E',
|
||||
replace: true,
|
||||
template,
|
||||
controller: function ($scope) {
|
||||
controller: function ($scope, i18n) {
|
||||
// force job ids to be lowercase
|
||||
$scope.changeJobIDCase = changeJobIDCase;
|
||||
$scope.hideAdvancedButtonAriaLabel = i18n('xpack.ml.newJob.simple.generalJobDetails.hideAdvancedButtonAriaLabel', {
|
||||
defaultMessage: 'Hide Advanced'
|
||||
});
|
||||
$scope.showAdvancedButtonAriaLabel = i18n('xpack.ml.newJob.simple.generalJobDetails.showAdvancedButtonAriaLabel', {
|
||||
defaultMessage: 'Show Advanced'
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<div class="influencers-selection">
|
||||
<div>
|
||||
<h4 class="euiTitle euiTitle--small">Key Fields (Influencers)</h4>
|
||||
<h4
|
||||
class="euiTitle euiTitle--small"
|
||||
i18n-id="xpack.ml.newJob.simple.influencersSelection.keyFieldsTitle"
|
||||
i18n-default-message="Key Fields (Influencers)"
|
||||
></h4>
|
||||
<div class="euiSpacer euiSpacer--s"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -15,7 +19,7 @@
|
|||
multiple
|
||||
append-to-body=true
|
||||
>
|
||||
<ui-select-match placeholder="Key fields">
|
||||
<ui-select-match placeholder="{{ ::'xpack.ml.newJob.simple.influencersSelection.keyFieldsAriaLabel' | i18n: {defaultMessage: 'Key fields'} }}">
|
||||
<span ng-class="{'default-influencer': isDefaultInfluencer($item)}">
|
||||
<ml-field-type-icon type="$item.mlType"></ml-field-type-icon>{{$item.name}}
|
||||
</span>
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
<label class='kuiCheckBoxLabel kuiVerticalRhythm'>
|
||||
<input ng-model='runInRealtime' ng-disabled="status.realtimeJob!==null" type="checkbox" class='kuiCheckBox' ng-click="clickRunInRealtime()"/>
|
||||
<span class="kuiCheckBoxLabel__text">
|
||||
Continue job in real-time
|
||||
<span
|
||||
i18n-id="xpack.ml.newJob.simple.postSaveOptions.continueJobInRealTimeLabel"
|
||||
i18n-default-message="Continue job in real-time"
|
||||
></span>
|
||||
<span ng-hide="status.realtimeJob===null">
|
||||
<i ng-show="status.realtimeJob === STATUS.SAVE_FAILED" aria-hidden="true" style="color:red;" class="fa fa-remove"></i>
|
||||
<i ng-show="status.realtimeJob === STATUS.SAVING" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
|
||||
|
@ -19,7 +22,10 @@
|
|||
ng-class="{'disabled': !runInRealtime}">
|
||||
<input ng-model='createWatch' ng-disabled="!runInRealtime || status.realtimeJob!==null" type="checkbox" class='kuiCheckBox' />
|
||||
<span class="kuiCheckBoxLabel__text">
|
||||
Create watch for real-time job
|
||||
<span
|
||||
i18n-id="xpack.ml.newJob.simple.postSaveOptions.createWatchForRealTimeJobLabel"
|
||||
i18n-default-message="Create watch for real-time job"
|
||||
></span>
|
||||
<span ng-hide="status.watch===null">
|
||||
<i ng-show="status.watch === STATUS.SAVE_FAILED" aria-hidden="true" style="color:red;" class="fa fa-remove"></i>
|
||||
<i ng-show="status.watch === STATUS.SAVING" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
|
||||
|
@ -39,13 +45,14 @@
|
|||
</div>
|
||||
|
||||
<button
|
||||
aria-label="Create watch"
|
||||
aria-label="{{ ::'xpack.ml.newJob.simple.postSaveOptions.createWatchButtonAriaLabel' | i18n: {defaultMessage: 'Create watch'} }}"
|
||||
ng-click="apply()"
|
||||
ng-hide='(status.realtimeJob===STATUS.SAVED && createWatch===false) || (status.realtimeJob===STATUS.SAVED && status.watch===STATUS.SAVED && createWatch===true)'
|
||||
ng-disabled='runInRealtime===false'
|
||||
type="button"
|
||||
class="kuiButton kuiButton--primary">
|
||||
Apply
|
||||
class="kuiButton kuiButton--primary"
|
||||
i18n-id="xpack.ml.newJob.simple.postSaveOptions.applyButtonLabel"
|
||||
i18n-default-message="Apply">
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@ import template from './post_save_options.html';
|
|||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
|
||||
module.directive('mlPostSaveOptions', function (Private) {
|
||||
module.directive('mlPostSaveOptions', function (Private, i18n) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: false,
|
||||
|
@ -43,7 +43,7 @@ module.directive('mlPostSaveOptions', function (Private) {
|
|||
};
|
||||
|
||||
$scope.apply = function () {
|
||||
postSaveService.apply($scope.jobId, $scope.runInRealtime, $scope.createWatch);
|
||||
postSaveService.apply($scope.jobId, $scope.runInRealtime, $scope.createWatch, i18n);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ class PostSaveService {
|
|||
this.externalCreateWatch;
|
||||
}
|
||||
|
||||
startRealtimeJob(jobId) {
|
||||
startRealtimeJob(jobId, i18n) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.status.realtimeJob = this.STATUS.SAVING;
|
||||
|
||||
|
@ -43,7 +43,10 @@ class PostSaveService {
|
|||
this.status.realtimeJob = this.STATUS.SAVED;
|
||||
resolve();
|
||||
}).catch((resp) => {
|
||||
msgs.error('Could not start datafeed: ', resp);
|
||||
msgs.error(
|
||||
i18n('xpack.ml.newJob.simple.postSaveOptions.couldNotStartDatafeedErrorMessage', {
|
||||
defaultMessage: 'Could not start datafeed:'
|
||||
}), resp);
|
||||
this.status.realtimeJob = this.STATUS.SAVE_FAILED;
|
||||
reject();
|
||||
});
|
||||
|
@ -52,9 +55,9 @@ class PostSaveService {
|
|||
});
|
||||
}
|
||||
|
||||
apply(jobId, runInRealtime, createWatch) {
|
||||
apply(jobId, runInRealtime, createWatch, i18n) {
|
||||
if (runInRealtime) {
|
||||
this.startRealtimeJob(jobId)
|
||||
this.startRealtimeJob(jobId, i18n)
|
||||
.then(() => {
|
||||
if (createWatch) {
|
||||
mlCreateWatchService.createNewWatch(jobId);
|
||||
|
|
|
@ -10,6 +10,7 @@ import { EVENT_RATE_COUNT_FIELD } from 'plugins/ml/jobs/new_job/simple/component
|
|||
import { ML_JOB_FIELD_TYPES, KBN_FIELD_TYPES } from 'plugins/ml/../common/constants/field_types';
|
||||
import { getSafeAggregationName } from 'plugins/ml/../common/util/job_utils';
|
||||
import { kbnTypeToMLJobType } from 'plugins/ml/util/field_types_utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function createFields(scope, indexPattern) {
|
||||
const isPopulation = scope.formConfig.hasOwnProperty('overField');
|
||||
|
@ -31,7 +32,9 @@ export function createFields(scope, indexPattern) {
|
|||
const eventRateField = {
|
||||
id: EVENT_RATE_COUNT_FIELD,
|
||||
name: 'event rate',
|
||||
tooltip: 'System defined field',
|
||||
tooltip: i18n.translate('xpack.ml.newJob.simple.createFields.systemDefinedFieldTooltip', {
|
||||
defaultMessage: 'System defined field'
|
||||
}),
|
||||
isCountField: true,
|
||||
agg: countAgg,
|
||||
mlType: ML_JOB_FIELD_TYPES.NUMBER,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function filterAggTypes(aggTypes) {
|
||||
const filteredAggTypes = [];
|
||||
|
@ -30,12 +31,16 @@ export function filterAggTypes(aggTypes) {
|
|||
filteredAggTypes.push(type);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'High count';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.highCountLabel', {
|
||||
defaultMessage: 'High count'
|
||||
});
|
||||
typeCopy.mlName = 'high_count';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'Low count';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.lowCountLabel', {
|
||||
defaultMessage: 'Low count'
|
||||
});
|
||||
typeCopy.mlName = 'low_count';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
|
@ -43,27 +48,37 @@ export function filterAggTypes(aggTypes) {
|
|||
filteredAggTypes.push(type);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'High sum';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.highSumLabel', {
|
||||
defaultMessage: 'High sum'
|
||||
});
|
||||
typeCopy.mlName = 'high_sum';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'Low sum';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.lowSumLabel', {
|
||||
defaultMessage: 'Low sum'
|
||||
});
|
||||
typeCopy.mlName = 'low_sum';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
} else if (type.name === 'avg') {
|
||||
type.title = 'Mean';
|
||||
type.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.meanLabel', {
|
||||
defaultMessage: 'Mean'
|
||||
});
|
||||
type.mlName = 'mean';
|
||||
filteredAggTypes.push(type);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'High mean';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.highMeanLabel', {
|
||||
defaultMessage: 'High mean'
|
||||
});
|
||||
typeCopy.mlName = 'high_mean';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'Low mean';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.lowMeanLabel', {
|
||||
defaultMessage: 'Low mean'
|
||||
});
|
||||
typeCopy.mlName = 'low_mean';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
|
@ -72,12 +87,16 @@ export function filterAggTypes(aggTypes) {
|
|||
filteredAggTypes.push(type);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'High median';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.highMedianLabel', {
|
||||
defaultMessage: 'High median'
|
||||
});
|
||||
typeCopy.mlName = 'high_median';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
typeCopy = angular.copy(type);
|
||||
typeCopy.title = 'Low median';
|
||||
typeCopy.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.lowMedianLabel', {
|
||||
defaultMessage: 'Low median'
|
||||
});
|
||||
typeCopy.mlName = 'low_median';
|
||||
filteredAggTypes.push(typeCopy);
|
||||
|
||||
|
@ -87,7 +106,9 @@ export function filterAggTypes(aggTypes) {
|
|||
} else if (type.name === 'max') {
|
||||
filteredAggTypes.push(type);
|
||||
} else if (type.name === 'cardinality') {
|
||||
type.title = 'Distinct count';
|
||||
type.title = i18n.translate('xpack.ml.newJob.simple.filterAggTypes.distinctCountLabel', {
|
||||
defaultMessage: 'Distinct count'
|
||||
});
|
||||
type.mlName = 'distinct_count';
|
||||
type.mlModelPlotAgg = { max: 'max', min: 'min' };
|
||||
type.isAggregatableStringType = true;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { basicJobValidation } from 'plugins/ml/../common/util/job_utils';
|
|||
import { newJobLimits } from 'plugins/ml/jobs/new_job/utils/new_job_defaults';
|
||||
import { ALLOWED_DATA_UNITS } from 'plugins/ml/../common/constants/validation';
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function validateJob(job, checks) {
|
||||
const limits = newJobLimits();
|
||||
|
@ -39,34 +40,46 @@ export function populateValidationMessages(validationResults, checks) {
|
|||
checks.jobId.valid = false;
|
||||
} else if (validationResults.contains('job_id_invalid')) {
|
||||
checks.jobId.valid = false;
|
||||
let msg = 'Job name can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ';
|
||||
msg += 'must start and end with an alphanumeric character';
|
||||
const msg = i18n.translate('xpack.ml.newJob.simple.validateJob.jobNameAllowedCharactersDescription', {
|
||||
defaultMessage: 'Job name can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ' +
|
||||
'must start and end with an alphanumeric character'
|
||||
});
|
||||
checks.jobId.message = msg;
|
||||
}
|
||||
|
||||
if (validationResults.contains('job_group_id_invalid')) {
|
||||
checks.groupIds.valid = false;
|
||||
let msg = 'Job group names can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ';
|
||||
msg += 'must start and end with an alphanumeric character';
|
||||
const msg = i18n.translate('xpack.ml.newJob.simple.validateJob.jobGroupAllowedCharactersDescription', {
|
||||
defaultMessage: 'Job group names can contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; ' +
|
||||
'must start and end with an alphanumeric character'
|
||||
});
|
||||
checks.groupIds.message = msg;
|
||||
}
|
||||
|
||||
if (validationResults.contains('model_memory_limit_units_invalid')) {
|
||||
checks.modelMemoryLimit.valid = false;
|
||||
const str = `${(ALLOWED_DATA_UNITS.slice(0, ALLOWED_DATA_UNITS.length - 1).join(', '))} or ${([...ALLOWED_DATA_UNITS].pop())}`;
|
||||
const msg = `Model memory limit data unit unrecognized. It must be ${str}`;
|
||||
const msg = i18n.translate('xpack.ml.newJob.simple.validateJob.modelMemoryLimitUnitsInvalidErrorMessage', {
|
||||
defaultMessage: 'Model memory limit data unit unrecognized. It must be {str}',
|
||||
values: { str }
|
||||
});
|
||||
checks.modelMemoryLimit.message = msg;
|
||||
}
|
||||
|
||||
if (validationResults.contains('model_memory_limit_invalid')) {
|
||||
checks.modelMemoryLimit.valid = false;
|
||||
const msg = `Model memory limit cannot be higher than the maximum value of ${limits.max_model_memory_limit.toUpperCase()}`;
|
||||
const msg = i18n.translate('xpack.ml.newJob.simple.validateJob.modelMemoryLimitRangeInvalidErrorMessage', {
|
||||
defaultMessage: 'Model memory limit cannot be higher than the maximum value of {maxModelMemoryLimit}',
|
||||
values: { maxModelMemoryLimit: limits.max_model_memory_limit.toUpperCase() }
|
||||
});
|
||||
checks.modelMemoryLimit.message = msg;
|
||||
}
|
||||
|
||||
if (validationResults.contains('detectors_duplicates')) {
|
||||
checks.duplicateDetectors.valid = false;
|
||||
const msg = 'Duplicate detectors were found.';
|
||||
const msg = i18n.translate('xpack.ml.newJob.simple.validateJob.duplicatedDetectorsErrorMessage', {
|
||||
defaultMessage: 'Duplicate detectors were found.',
|
||||
});
|
||||
checks.duplicateDetectors.message = msg;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,26 @@
|
|||
<div ng-show="status.watch===null || status.watch===STATUS.SAVING || status.watch===STATUS.SAVE_FAILED">
|
||||
<div class="form-group">
|
||||
<div class="sub-form-group">
|
||||
<label for="selectInterval" class="kuiFormLabel kuiVerticalRhythm">Time range</label><br />
|
||||
Now - <input id="selectInterval" ng-model="config.interval" type="text" class="kuiTextInput kuiTextInput--small interval" placeholder="m">
|
||||
<label
|
||||
for="selectInterval"
|
||||
class="kuiFormLabel kuiVerticalRhythm"
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.timeRangeLabel"
|
||||
i18n-default-message="Time range"
|
||||
></label><br />
|
||||
<span
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.nowLabel"
|
||||
i18n-default-message="Now -"
|
||||
></span>
|
||||
<input id="selectInterval" ng-model="config.interval" type="text" class="kuiTextInput kuiTextInput--small interval" placeholder="m">
|
||||
</div>
|
||||
|
||||
<div class="sub-form-group">
|
||||
<label for="selectSeverity" class="kuiFormLabel kuiVerticalRhythm">Severity threshold</label><br />
|
||||
<label
|
||||
for="selectSeverity"
|
||||
class="kuiFormLabel kuiVerticalRhythm"
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.severityThresholdLabel"
|
||||
i18n-default-message="Severity threshold"
|
||||
></label><br />
|
||||
<div class="dropdown-group">
|
||||
<ml-severity-control
|
||||
config='config'
|
||||
|
@ -18,24 +32,47 @@
|
|||
<div ng-show="ui.emailEnabled" class="form-group">
|
||||
<label for="sendEmail" class="kuiCheckBoxLabel kuiVerticalRhythm">
|
||||
<input id="sendEmail" ng-model="config.includeEmail" type="checkbox" class="kuiCheckBox" />
|
||||
<span class="kuiCheckBoxLabel__text">Send email</span>
|
||||
<span
|
||||
class="kuiCheckBoxLabel__text"
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.sendEmailLabel"
|
||||
i18n-default-message="Send email"
|
||||
></span>
|
||||
</label>
|
||||
<div ng-show="config.includeEmail" class="email-section">
|
||||
<input type="text" ng-model="config.email" class="kuiTextInput kuiTextInput--large" placeholder="email address">
|
||||
<input
|
||||
type="text"
|
||||
ng-model="config.email"
|
||||
class="kuiTextInput kuiTextInput--large"
|
||||
placeholder="{{ ::'xpack.ml.newJob.simple.createWatch.emailAddressPlaceholder' | i18n: {defaultMessage: 'email address'} }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="ui.watchAlreadyExists" class="watch-exists-warning">
|
||||
Warning, watch ml-{{jobId}} already exists, clicking apply will overwrite the original.
|
||||
<div
|
||||
ng-if="ui.watchAlreadyExists"
|
||||
class="watch-exists-warning"
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.watchAlreadyExistsWarningMessage"
|
||||
i18n-default-message="Warning, watch ml-{jobId} already exists, clicking apply will overwrite the original."
|
||||
i18n-values="{ jobId }"
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="status.watch===STATUS.SAVED">
|
||||
<div>Watch: <strong>{{config.id}}</strong> created</div>
|
||||
<div
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.watchCreatedLabel"
|
||||
i18n-default-message="Watch: {id} created"
|
||||
i18n-values="{ html_id: '<strong>' + config.id + '</strong>' }"
|
||||
></div>
|
||||
<br />
|
||||
<div>
|
||||
<a href="{{config.watcherEditURL}}" target="_blank" rel="noopener noreferrer">Edit {{config.id}} in Watcher <i class="fa fa-external-link"></i></a>
|
||||
<a href="{{config.watcherEditURL}}" target="_blank" rel="noopener noreferrer">
|
||||
<span
|
||||
i18n-id="xpack.ml.newJob.simple.createWatch.editWatchLinkText"
|
||||
i18n-default-message="Edit {id} in Watcher"
|
||||
i18n-values="{ id: config.id }"
|
||||
></span>
|
||||
<i class="fa fa-external-link"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -26,13 +26,19 @@ import {
|
|||
import { has } from 'lodash';
|
||||
|
||||
import { parseInterval } from 'ui/utils/parse_interval';
|
||||
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { SelectSeverity } from '../../../../../components/controls/select_severity/select_severity';
|
||||
import { mlCreateWatchService } from './create_watch_service';
|
||||
const STATUS = mlCreateWatchService.STATUS;
|
||||
|
||||
export class CreateWatch extends Component {
|
||||
export const CreateWatch = injectI18n(class CreateWatch extends Component {
|
||||
static propTypes = {
|
||||
jobId: PropTypes.string.isRequired,
|
||||
bucketSpan: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
mlCreateWatchService.reset();
|
||||
|
@ -111,6 +117,7 @@ export class CreateWatch extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { intl } = this.props;
|
||||
const mlSelectSeverityService = {
|
||||
state: {
|
||||
set: (name, threshold) => {
|
||||
|
@ -136,13 +143,22 @@ export class CreateWatch extends Component {
|
|||
htmlFor="selectInterval"
|
||||
className="euiFormLabel"
|
||||
>
|
||||
Time range
|
||||
<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.timeRangeLabel"
|
||||
defaultMessage="Time range"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
Now - <EuiFieldText
|
||||
id="selectInterval"
|
||||
value={this.state.interval}
|
||||
onChange={this.onIntervalChange}
|
||||
<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.nowLabel"
|
||||
defaultMessage="Now - {selectInterval}"
|
||||
values={{ selectInterval: (
|
||||
<EuiFieldText
|
||||
id="selectInterval"
|
||||
value={this.state.interval}
|
||||
onChange={this.onIntervalChange}
|
||||
/>
|
||||
) }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -152,7 +168,10 @@ export class CreateWatch extends Component {
|
|||
htmlFor="selectSeverity"
|
||||
className="euiFormLabel"
|
||||
>
|
||||
Severity threshold
|
||||
<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.severityThresholdLabel"
|
||||
defaultMessage="Severity threshold"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className="dropdown-group">
|
||||
|
@ -169,7 +188,10 @@ export class CreateWatch extends Component {
|
|||
<div className="form-group">
|
||||
<EuiCheckbox
|
||||
id="includeEmail"
|
||||
label="Send email"
|
||||
label={<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.sendEmailLabel"
|
||||
defaultMessage="Send email"
|
||||
/>}
|
||||
checked={this.state.includeEmail}
|
||||
onChange={this.onIncludeEmailChanged}
|
||||
/>
|
||||
|
@ -179,8 +201,14 @@ export class CreateWatch extends Component {
|
|||
<EuiFieldText
|
||||
value={this.state.email}
|
||||
onChange={this.onEmailChange}
|
||||
placeholder="email address"
|
||||
aria-label="Watch email address"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'xpack.ml.newJob.simple.createWatchView.emailAddressPlaceholder',
|
||||
defaultMessage: 'email address'
|
||||
})}
|
||||
aria-label={intl.formatMessage({
|
||||
id: 'xpack.ml.newJob.simple.createWatchView.watchEmailAddressAriaLabel',
|
||||
defaultMessage: 'Watch email address'
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
@ -189,21 +217,28 @@ export class CreateWatch extends Component {
|
|||
{
|
||||
this.state.watchAlreadyExists &&
|
||||
<EuiCallOut
|
||||
title={`Warning, watch ml-${this.state.jobId} already exists, clicking apply will overwrite the original.`}
|
||||
title={<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.watchAlreadyExistsWarningMessage"
|
||||
defaultMessage="Warning, watch ml-{jobId} already exists, clicking apply will overwrite the original."
|
||||
values={{
|
||||
jobId: this.state.jobId
|
||||
}}
|
||||
/>}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
} else if (status === STATUS.SAVED) {
|
||||
return (
|
||||
<div>Success</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.newJob.simple.createWatchView.successLabel"
|
||||
defaultMessage="Success"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (<div />);
|
||||
}
|
||||
}
|
||||
}
|
||||
CreateWatch.propTypes = {
|
||||
jobId: PropTypes.string.isRequired,
|
||||
bucketSpan: PropTypes.string.isRequired,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<strong>Top influencers:</strong>
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.emailInfluencers.topInfluencersLabel' '{"defaultMessage": "Top influencers:"'}}
|
||||
</strong>
|
||||
<br />
|
||||
{{#ctx.payload.aggregations.influencer_results.top_influencer_hits.hits.hits}}
|
||||
{{_source.influencer_field_name}} = {{_source.influencer_field_value}} [{{fields.score.0}}]
|
||||
|
|
|
@ -1,27 +1,38 @@
|
|||
<html>
|
||||
<body>
|
||||
<strong>Elastic Stack Machine Learning Alert</strong>
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.email.elasticStackMachineLearningAlertLabel' '{"defaultMessage": "Elastic Stack Machine Learning Alert"'}}
|
||||
</strong>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<strong>Job</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0._source.job_id}}
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.email.jobLabel' '{"defaultMessage": "Job"'}}
|
||||
</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0._source.job_id}}
|
||||
<br />
|
||||
|
||||
<strong>Time</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.timestamp_iso8601.0}}
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.email.timeLabel' '{"defaultMessage": "Time"'}}
|
||||
</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.timestamp_iso8601.0}}
|
||||
<br />
|
||||
|
||||
<strong>Anomaly score</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.score.0}}
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.email.anomalyScoreLabel' '{"defaultMessage": "Anomaly score"'}}
|
||||
</strong>: {{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.score.0}}
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<a href="<%= serverAddress %>#/explorer/?_g=(ml:(jobIds:!('{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0._source.job_id}}')),refreshInterval:(display:Off,pause:!f,value:0),time:(from:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.start.0}}',mode:absolute,to:'{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.end.0}}'))&_a=(filters:!(),mlAnomaliesTable:(intervalValue:auto,thresholdValue:0),mlExplorerSwimlane:(selectedLane:Overall,selectedTime:{{ctx.payload.aggregations.bucket_results.top_bucket_hits.hits.hits.0.fields.timestamp_epoch.0}},selectedType:overall),query:(query_string:(analyze_wildcard:!t,query:'*')))">
|
||||
Click here to open in Anomaly Explorer</a>.
|
||||
{{i18n 'xpack.ml.newJob.simple.email.openInAnomalyExplorerLinkText' '{"defaultMessage": "Click here to open in Anomaly Explorer."'}}
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<%= influencersSection %>
|
||||
|
||||
<strong>Top records:</strong>
|
||||
<strong>
|
||||
{{i18n 'xpack.ml.newJob.simple.email.topRecordsLabel' '{"defaultMessage": "Top records:"'}}
|
||||
</strong>
|
||||
<br />
|
||||
{{#ctx.payload.aggregations.record_results.top_record_hits.hits.hits}}
|
||||
{{_source.function}}({{_source.field_name}}) {{_source.by_field_value}} {{_source.over_field_value}} {{_source.partition_field_value}} [{{fields.score.0}}]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue