diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js index b463322ea55d..3508d69ee221 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js @@ -48,6 +48,8 @@ export class EditJobFlyoutUI extends Component { jobDescription: '', jobGroups: [], jobModelMemoryLimit: '', + jobModelSnapshotRetentionDays: 10, + jobDailyModelSnapshotRetentionAfterDays: 10, jobDetectors: [], jobDetectorDescriptions: [], jobCustomUrls: [], @@ -96,6 +98,8 @@ export class EditJobFlyoutUI extends Component { 'jobDescription', 'jobGroups', 'jobModelMemoryLimit', + 'jobModelSnapshotRetentionDays', + 'jobDailyModelSnapshotRetentionAfterDays', 'jobCustomUrls', 'jobDetectors', 'jobDetectorDescriptions', @@ -128,6 +132,15 @@ export class EditJobFlyoutUI extends Component { job.analysis_limits && job.analysis_limits.model_memory_limit ? job.analysis_limits.model_memory_limit : ''; + + const modelSnapshotRetentionDays = + job.model_snapshot_retention_days !== undefined ? job.model_snapshot_retention_days : 10; + + const dailyModelSnapshotRetentionAfterDays = + job.daily_model_snapshot_retention_after_days !== undefined + ? job.daily_model_snapshot_retention_after_days + : modelSnapshotRetentionDays; + const detectors = job.analysis_config && job.analysis_config.detectors ? [...job.analysis_config.detectors] @@ -146,6 +159,8 @@ export class EditJobFlyoutUI extends Component { jobDescription: job.description, jobGroups: job.groups !== undefined ? job.groups : [], jobModelMemoryLimit: mml, + jobModelSnapshotRetentionDays: modelSnapshotRetentionDays, + jobDailyModelSnapshotRetentionAfterDays: dailyModelSnapshotRetentionAfterDays, jobDetectors: detectors, jobDetectorDescriptions: detectors.map((d) => d.detector_description), jobBucketSpan: bucketSpan, @@ -229,6 +244,8 @@ export class EditJobFlyoutUI extends Component { description: this.state.jobDescription, groups: this.state.jobGroups, mml: this.state.jobModelMemoryLimit, + modelSnapshotRetentionDays: this.state.jobModelSnapshotRetentionDays, + dailyModelSnapshotRetentionAfterDays: this.state.jobDailyModelSnapshotRetentionAfterDays, detectorDescriptions: this.state.jobDetectorDescriptions, datafeedQuery: collapseLiteralStrings(this.state.datafeedQuery), datafeedQueryDelay: this.state.datafeedQueryDelay, @@ -275,6 +292,8 @@ export class EditJobFlyoutUI extends Component { jobDescription, jobGroups, jobModelMemoryLimit, + jobModelSnapshotRetentionDays, + jobDailyModelSnapshotRetentionAfterDays, jobDetectors, jobDetectorDescriptions, jobBucketSpan, @@ -302,6 +321,8 @@ export class EditJobFlyoutUI extends Component { jobDescription={jobDescription} jobGroups={jobGroups} jobModelMemoryLimit={jobModelMemoryLimit} + jobModelSnapshotRetentionDays={jobModelSnapshotRetentionDays} + jobDailyModelSnapshotRetentionAfterDays={jobDailyModelSnapshotRetentionAfterDays} setJobDetails={this.setJobDetails} jobGroupsValidationError={jobGroupsValidationError} jobModelMemoryLimitValidationError={jobModelMemoryLimitValidationError} diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.js index fcd2c09f7276..5030c48a4e36 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_utils.js @@ -16,6 +16,8 @@ export function saveJob(job, newJobData, finish) { ...extractDescription(job, newJobData), ...extractGroups(job, newJobData), ...extractMML(job, newJobData), + ...extractModelSnapshotRetentionDays(job, newJobData), + ...extractDailyModelSnapshotRetentionAfterDays(job, newJobData), ...extractDetectorDescriptions(job, newJobData), ...extractCustomSettings(job, newJobData), }; @@ -175,6 +177,22 @@ function extractMML(job, newJobData) { return mmlData; } +function extractModelSnapshotRetentionDays(job, newJobData) { + const modelSnapshotRetentionDays = newJobData.modelSnapshotRetentionDays; + if (modelSnapshotRetentionDays !== job.model_snapshot_retention_days) { + return { model_snapshot_retention_days: modelSnapshotRetentionDays }; + } + return {}; +} + +function extractDailyModelSnapshotRetentionAfterDays(job, newJobData) { + const dailyModelSnapshotRetentionAfterDays = newJobData.dailyModelSnapshotRetentionAfterDays; + if (dailyModelSnapshotRetentionAfterDays !== job.daily_model_snapshot_retention_after_days) { + return { daily_model_snapshot_retention_after_days: dailyModelSnapshotRetentionAfterDays }; + } + return {}; +} + function extractDetectorDescriptions(job, newJobData) { const detectors = []; const descriptions = newJobData.detectorDescriptions.map((d, i) => ({ diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/job_details.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/job_details.js index 974afafc08b6..ec5ef6fce26b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/job_details.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/job_details.js @@ -7,7 +7,14 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiComboBox } from '@elastic/eui'; +import { + EuiFieldText, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiComboBox, + EuiFieldNumber, +} from '@elastic/eui'; import { ml } from '../../../../../services/ml_api_service'; import { i18n } from '@kbn/i18n'; @@ -24,6 +31,8 @@ export class JobDetails extends Component { mml: '', mmlValidationError: '', groupsValidationError: '', + modelSnapshotRetentionDays: 1, + dailyModelSnapshotRetentionAfterDays: 1, }; this.setJobDetails = props.setJobDetails; @@ -52,6 +61,8 @@ export class JobDetails extends Component { mml: props.jobModelMemoryLimit, mmlValidationError: props.jobModelMemoryLimitValidationError, groupsValidationError: props.jobGroupsValidationError, + modelSnapshotRetentionDays: props.jobModelSnapshotRetentionDays, + dailyModelSnapshotRetentionAfterDays: props.jobDailyModelSnapshotRetentionAfterDays, }; } @@ -63,6 +74,24 @@ export class JobDetails extends Component { this.setJobDetails({ jobModelMemoryLimit: e.target.value }); }; + onModelSnapshotRetentionDaysChange = (e) => { + const jobModelSnapshotRetentionDays = Math.floor(+e.target.value); + + this.setJobDetails({ + jobModelSnapshotRetentionDays, + ...(this.state.dailyModelSnapshotRetentionAfterDays > jobModelSnapshotRetentionDays + ? { jobDailyModelSnapshotRetentionAfterDays: jobModelSnapshotRetentionDays } + : {}), + }); + }; + + onDailyModelSnapshotRetentionAfterDaysChange = (e) => { + const jobDailyModelSnapshotRetentionAfterDays = Math.floor(+e.target.value); + if (jobDailyModelSnapshotRetentionAfterDays <= this.state.modelSnapshotRetentionDays) { + this.setJobDetails({ jobDailyModelSnapshotRetentionAfterDays }); + } + }; + onGroupsChange = (selectedGroups) => { this.setJobDetails({ jobGroups: selectedGroups.map((g) => g.label) }); }; @@ -104,6 +133,8 @@ export class JobDetails extends Component { groups, mmlValidationError, groupsValidationError, + modelSnapshotRetentionDays, + dailyModelSnapshotRetentionAfterDays, } = this.state; const { datafeedRunning } = this.props; return ( @@ -172,6 +203,35 @@ export class JobDetails extends Component { disabled={datafeedRunning} /> + + } + > + + + + } + > + + ); diff --git a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts index de393e002c55..3a01a616a4f7 100644 --- a/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/anomaly_detectors_schema.ts @@ -69,6 +69,7 @@ export const anomalyDetectionUpdateJobSchema = schema.object({ }) ), groups: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), + model_snapshot_retention_days: schema.maybe(schema.number()), }); export const analysisConfigSchema = schema.object({