diff --git a/x-pack/plugins/ml/public/components/json_tooltip/tooltips.json b/x-pack/plugins/ml/public/components/json_tooltip/tooltips.json
index 84a9f2cc27912d..b6cbc55699822c 100644
--- a/x-pack/plugins/ml/public/components/json_tooltip/tooltips.json
+++ b/x-pack/plugins/ml/public/components/json_tooltip/tooltips.json
@@ -107,6 +107,9 @@
"new_job_dedicated_index": {
"text": "Select to store results in a separate index for this job."
},
+ "new_job_enable_model_plot": {
+ "text": "Select to enable model plot. Stores model information along with results. Can add considerable overhead to the performance of the system."
+ },
"new_job_model_memory_limit": {
"text": "An approximate limit for the amount of memory used by the analytical models."
},
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox.test.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox.test.js
new file mode 100644
index 00000000000000..5e73541a99bece
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox.test.js
@@ -0,0 +1,40 @@
+/*
+ * 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 React from 'react';
+import { mount } from 'enzyme';
+import { EnableModelPlotCheckbox } from './enable_model_plot_checkbox_view.js';
+
+const defaultProps = {
+ checkboxText: 'Enable model plot',
+ onCheckboxChange: () => {},
+ warningStatus: false,
+ warningContent: 'Test warning content',
+};
+
+describe('EnableModelPlotCheckbox', () => {
+
+ test('checkbox default is rendered correctly', () => {
+ const wrapper = mount();
+ const checkbox = wrapper.find({ type: 'checkbox' });
+ const label = wrapper.find('label');
+
+ expect(checkbox.props().checked).toBe(false);
+ expect(label.text()).toBe('Enable model plot');
+ });
+
+ test('onCheckboxChange function prop is called when checkbox is toggled', () => {
+ const mockOnChange = jest.fn();
+ defaultProps.onCheckboxChange = mockOnChange;
+
+ const wrapper = mount();
+ const checkbox = wrapper.find({ type: 'checkbox' });
+
+ checkbox.simulate('change', { target: { checked: true } });
+ expect(mockOnChange).toBeCalled();
+ });
+
+});
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_directive.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_directive.js
new file mode 100644
index 00000000000000..e153c695994bde
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_directive.js
@@ -0,0 +1,154 @@
+/*
+ * 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 React from 'react';
+import ReactDOM from 'react-dom';
+
+import { EnableModelPlotCheckbox } from './enable_model_plot_checkbox_view.js';
+import { ml } from '../../../../../services/ml_api_service';
+
+import { uiModules } from 'ui/modules';
+const module = uiModules.get('apps/ml');
+
+module.directive('mlEnableModelPlotCheckbox', function () {
+ return {
+ restrict: 'AE',
+ replace: false,
+ scope: {
+ formConfig: '=',
+ ui: '=ui',
+ getJobFromConfig: '='
+ },
+ link: function ($scope, $element) {
+ const STATUS = {
+ FAILED: -1,
+ NOT_RUNNING: 0,
+ RUNNING: 1,
+ FINISHED: 2,
+ WARNING: 3,
+ };
+
+ function errorHandler(error) {
+ console.log('Cardinality could not be validated', error);
+ $scope.ui.cardinalityValidator.status = STATUS.FAILED;
+ $scope.ui.cardinalityValidator.message = 'Cardinality could not be validated';
+ }
+
+ // Only model plot cardinality relevant
+ // format:[{id:"cardinality_model_plot_high",modelPlotCardinality:11405}, {id:"cardinality_partition_field",fieldName:"clientip"}]
+ function checkCardinalitySuccess(data) {
+ const response = {
+ success: true,
+ };
+ // There were no fields to run cardinality on.
+ if (Array.isArray(data) && data.length === 0) {
+ return response;
+ }
+
+ for (let i = 0; i < data.length; i++) {
+ if (data[i].id === 'success_cardinality') {
+ break;
+ }
+
+ if (data[i].id === 'cardinality_model_plot_high') {
+ response.success = false;
+ response.highCardinality = data[i].modelPlotCardinality;
+ break;
+ }
+ }
+
+ return response;
+ }
+
+ function validateCardinality() {
+ $scope.ui.cardinalityValidator.status = STATUS.RUNNING;
+ $scope.ui.cardinalityValidator.message = '';
+
+ // create temporary job since cardinality validation expects that format
+ const tempJob = $scope.getJobFromConfig($scope.formConfig);
+
+ ml.validateCardinality(tempJob)
+ .then((response) => {
+ const validationResult = checkCardinalitySuccess(response);
+
+ 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.status = STATUS.WARNING;
+ // Go ahead and check the dedicated index box for them
+ $scope.formConfig.useDedicatedIndex = true;
+ // show the advanced section so the warning message is visible since validation failed
+ $scope.ui.showAdvanced = true;
+ }
+ })
+ .catch(errorHandler);
+ }
+
+ // Re-validate cardinality for updated fields/splitField
+ // when enable model plot is checked and form valid
+ function revalidateCardinalityOnFieldChange() {
+ if ($scope.formConfig.enableModelPlot === true && $scope.ui.formValid === true) {
+ validateCardinality();
+ }
+ }
+
+ $scope.handleCheckboxChange = (isChecked) => {
+ if (isChecked) {
+ $scope.formConfig.enableModelPlot = true;
+ validateCardinality();
+ } else {
+ $scope.formConfig.enableModelPlot = false;
+ $scope.ui.cardinalityValidator.status = STATUS.FINISHED;
+ $scope.ui.cardinalityValidator.message = '';
+ updateCheckbox();
+ }
+ };
+
+ // Update checkbox on these changes
+ $scope.$watch('ui.formValid', updateCheckbox, true);
+ $scope.$watch('ui.cardinalityValidator.status', updateCheckbox, true);
+ // MultiMetric: Fire off cardinality validatation when fields and/or split by field is updated
+ $scope.$watch('formConfig.fields', revalidateCardinalityOnFieldChange, true);
+ $scope.$watch('formConfig.splitField', revalidateCardinalityOnFieldChange, true);
+ // Population: Fire off cardinality validatation when overField is updated
+ $scope.$watch('formConfig.overField', revalidateCardinalityOnFieldChange, true);
+
+ function updateCheckbox() {
+ // disable if (check is running && checkbox checked) or (form is invalid && checkbox unchecked)
+ const checkboxDisabled = (
+ ($scope.ui.cardinalityValidator.status === STATUS.RUNNING &&
+ $scope.formConfig.enableModelPlot === true) ||
+ ($scope.ui.formValid !== true &&
+ $scope.formConfig.enableModelPlot === false)
+ );
+ const validatorRunning = ($scope.ui.cardinalityValidator.status === STATUS.RUNNING);
+ const warningStatus = ($scope.ui.cardinalityValidator.status === STATUS.WARNING && $scope.ui.formValid === true);
+ const checkboxText = (validatorRunning) ? 'Validating cardinality...' : 'Enable model plot';
+
+ const props = {
+ checkboxDisabled,
+ checkboxText,
+ onCheckboxChange: $scope.handleCheckboxChange,
+ warningContent: $scope.ui.cardinalityValidator.message,
+ warningStatus,
+ };
+
+ ReactDOM.render(
+ React.createElement(EnableModelPlotCheckbox, props),
+ $element[0]
+ );
+ }
+
+ updateCheckbox();
+ }
+ };
+});
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_view.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_view.js
new file mode 100644
index 00000000000000..a01e63dc7625f6
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/enable_model_plot_checkbox_view.js
@@ -0,0 +1,92 @@
+/*
+ * 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 PropTypes from 'prop-types';
+import React, { Fragment, Component } from 'react';
+
+import {
+ EuiCallOut,
+ EuiCheckbox,
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '@elastic/eui';
+
+import { JsonTooltip } from '../../../../../components/json_tooltip/json_tooltip';
+
+
+export class EnableModelPlotCheckbox extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ checked: false,
+ };
+ }
+
+ warningTitle = 'Proceed with caution!';
+
+ onChange = (e) => {
+ this.setState({
+ checked: e.target.checked,
+ });
+ this.props.onCheckboxChange(e.target.checked);
+ };
+
+ renderWarningCallout = () => (
+
+
+
+
+
+ {this.props.warningContent}
+
+
+
+
+
+ );
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ { this.props.warningStatus && this.renderWarningCallout() }
+
+ );
+ }
+}
+
+EnableModelPlotCheckbox.propTypes = {
+ checkboxDisabled: PropTypes.bool,
+ checkboxText: PropTypes.string.isRequired,
+ onCheckboxChange: PropTypes.func.isRequired,
+ warningStatus: PropTypes.bool.isRequired,
+ warningContent: PropTypes.string.isRequired,
+};
+
+EnableModelPlotCheckbox.defaultProps = {
+ checkboxDisabled: false,
+};
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/index.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/index.js
new file mode 100644
index 00000000000000..574f51888697e0
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/enable_model_plot_checkbox/index.js
@@ -0,0 +1,8 @@
+/*
+ * 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 './enable_model_plot_checkbox_directive.js';
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/general_job_details.html b/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/general_job_details.html
index 1a055c2063b0bc..3dc1521dbd7bf3 100644
--- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/general_job_details.html
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/general_job_details/general_job_details.html
@@ -47,6 +47,13 @@
+
+
+
+