[ML] Removing old angular based start datafeed modal (#30392)

* [ML] Removing old and broken start datafeed modal

* fixing typos

* removing need to load job from server

* small refactor

* adding comments

* removing unnecessary async/await
This commit is contained in:
James Gowdy 2019-02-08 13:58:59 +00:00 committed by GitHub
parent beb4542079
commit 00949efc5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 40 additions and 441 deletions

View file

@ -1,4 +1,3 @@
@import 'components/custom_url_editor/index';
@import 'components/job_timepicker_modal/index';
@import 'jobs_list/index'; // SASSTODO: Various EUI overwrites throughout this folder
@import 'new_job/index'; // SASSTODO: Lots of files need rewrites in here

View file

@ -1 +0,0 @@
@import 'job_timepicker_modal';

View file

@ -1,85 +0,0 @@
.job-timepicker-modal {
font-size: $euiFontSizeS;
padding:$euiSize;
cursor: auto;
h3 {
overflow: hidden;
text-overflow: ellipsis;
}
.date_container {
width: 200px;
display: inline-block;
}
.ml-timepicker-contents {
margin-top: $euiSizeXS;
.btn-info.active, .kuiButton--primary.active {
color: $euiColorGhost;
background-color: #154751;
border-color: #134049;
span {
color: $euiColorGhost;
}
}
.btn-default, .kuiButton--basic {
background: transparent;
color: $euiTextColor;
border: 0px;
box-shadow: none;
text-shadow: none;
}
[ml-time-input] {
text-align: center;
}
label {
display: block;
}
}
.ml-timepicker-modes {
text-transform: capitalize;
}
.ml-timepicker-section {
float: left;
padding: 0px 15px;
min-width: 294px;
width: 294px;
border-left: 1px solid $euiColorGhost;
border-right: 1px solid $euiColorGhost;
.ml-timepicker {
padding: 13px;
padding-top: none;
border: $euiBorderThick;
border-radius: 4px;
border-radius: 4px;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-top: none;
.btn, .kuiButton {
padding-left: 8px;
padding-right: 8px;
}
}
.ml-timepicker-radio-bottom {
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
}
.ml-timepicker-left-border {
border-left: $euiBorderThin;
}
.ml-timepicker-right-border {
border-right: $euiBorderThin;
}
}

View file

@ -1,32 +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 jobTimePickerTemplate from './job_timepicker_modal.html';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.service('mlDatafeedService', function ($modal) {
this.openJobTimepickerWindow = function (job) {
$modal.open({
template: jobTimePickerTemplate,
controller: 'MlJobTimepickerModal',
backdrop: 'static',
keyboard: false,
resolve: {
params: function () {
return {
job
};
}
}
});
};
});

View file

@ -1,11 +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 './datafeed_service';
import './job_timepicker_modal_controller';
import 'plugins/ml/jobs/new_job/simple/components/watcher';

View file

@ -1,139 +0,0 @@
<div class="job-timepicker-modal">
<ml-message-bar ></ml-message-bar>
<h1
tooltip="{{ ::'xpack.ml.jobTimePickerModal.startDatafeedForJobTooltip' | i18n: {
defaultMessage: 'Start datafeed for {jobId}',
values: { jobId }
} }}"
class="euiTitle"
i18n-id="xpack.ml.jobTimePickerModal.startDatafeedForJobTitle"
i18n-default-message="Start datafeed for {jobId}"
i18n-values="{ jobId }"
></h1>
<div class="euiSpacer euiSpacer--s"></div>
<div class="ml-timepicker-contents" >
<div class="row">
<div
class="ml-timepicker-section"
ng-class="{
'ml-timepicker-right-border':
(+ui.startRadio <= 1 && ui.endRadio === '0') ||
(ui.startRadio === '2' && +ui.endRadio <= 1)
}">
<label
class="kuiFormLabel"
i18n-id="xpack.ml.jobTimePickerModal.searchStartTimeLabel"
i18n-default-message="Search start time"
></label>
<div class="ml-timepicker-radios" >
<ul class="nav nav-pills nav-stacked">
<li ng-class="{ active: ui.startRadio === '1' }">
<a ng-click="ui.startRadio = '1'" >{{ ( isNew ? startAtBeginningOfDataLabel : continueFromLastTimeLabel ) }}</a>
</li>
<li ng-class="{ active: ui.startRadio === '0' }">
<a ng-click="ui.startRadio = '0'">{{ ( isNew ? startNowLabel : continueFromNowLabel ) }}</a>
</li>
<li ng-class="{ active: ui.startRadio === '2' }">
<a ng-click="ui.startRadio = '2'" ng-class="{'ml-timepicker-radio-bottom': ui.startRadio === '2'}">{{ ( isNew ? specifyStartTimeLabel : continueFromSpecifiedTimeLabel ) }}</a>
</li>
</ul>
</div>
<div class='ml-timepicker' ng-show="ui.startRadio == '2'">
<div>
<input type="text" class="form-control" input-datetime="YYYY-MM-DD HH:mm:ss" ng-model="ui.timepicker.from" >
</div>
<div>
<datepicker
offset-timezone
ng-model="ui.timepicker.from"
show-weeks="false">
</datepicker>
</div>
</div>
</div>
<div class="ml-timepicker-section"
ng-class="{
'ml-timepicker-left-border':
(+ui.startRadio <= 1 && ui.endRadio === '1')
}">
<label
class="kuiFormLabel"
i18n-id="xpack.ml.jobTimePickerModal.searchEndTimeLabel"
i18n-default-message="Search end time"
></label>
<div class="ml-timepicker-radios" >
<ul class="nav nav-pills nav-stacked">
<li ng-class="{ active: ui.endRadio === '0' }">
<a
ng-click="ui.endRadio = '0'"
i18n-id="xpack.ml.jobTimePickerModal.noEndTimeLinkText"
i18n-default-message="No end time (Real-time search)"
></a>
</li>
<li ng-class="{ active: ui.endRadio === '1' }">
<a
ng-click="ui.endRadio = '1'"
ng-class="{'ml-timepicker-radio-bottom': ui.endRadio === '1'}"
i18n-id="xpack.ml.jobTimePickerModal.specifyEndTimeLinkText"
i18n-default-message="Specify end time"
></a>
</li>
</ul>
</div>
<div class='ml-timepicker' ng-show="ui.endRadio == '1'">
<div>
<input type="text" class="form-control" input-datetime="{{format}}" ng-model="ui.timepicker.to">
</div>
<div>
<datepicker
offset-timezone
ng-model="ui.timepicker.to"
show-weeks="false">
</datepicker>
</div>
</div>
</div>
</div>
</div>
<div ng-if="ui.endRadio === '0' && watcherEnabled">
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
<label class='kuiCheckBoxLabel kuiVerticalRhythm'>
<input ng-model='ui.createWatch' type="checkbox" class='kuiCheckBox'/>
<span
class="kuiCheckBoxLabel__text"
i18n-id="xpack.ml.jobTimePickerModal.createWatchAfterDatafeedHasStartedLabel"
i18n-default-message="Create watch after datafeed has started"
></span>
</label>
</div>
<div class="clearfix"></div>
<hr class="euiHorizontalRule euiHorizontalRule--full euiHorizontalRule--marginMedium">
<button
ng-click="save()"
ng-disabled="(
saveLock === true ||
( ui.startRadio==='2' && ui.timepicker.from==='' ) ||
( ui.endRadio==='1' && ui.timepicker.to==='' )
)"
class="kuiButton kuiButton--primary"
i18n-id="xpack.ml.jobTimePickerModal.startButtonLabel"
i18n-default-message="Start"
></button>
<button
ng-click="cancel()"
ng-disabled="(saveLock === true)"
class="kuiButton kuiButton--primary"
aria-label="{{ ::'xpack.ml.jobTimePickerModal.cancelButtonAriaLabel' | i18n: {defaultMessage: 'Cancel'} }}"
i18n-id="xpack.ml.jobTimePickerModal.cancelButtonLabel"
i18n-default-message="Cancel"
></button>
</div>

View file

@ -1,167 +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 moment from 'moment';
import angular from 'angular';
import { mlJobService } from 'plugins/ml/services/job_service';
import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar_service';
import { xpackFeatureProvider } from 'plugins/ml/license/check_license';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
module.controller('MlJobTimepickerModal', function (
$scope,
$rootScope,
$modalInstance,
params,
Private,
i18n) {
const msgs = mlMessageBarService;
$scope.saveLock = false;
const xpackFeature = Private(xpackFeatureProvider);
$scope.watcherEnabled = xpackFeature.isAvailable('watcher');
const job = angular.copy(params.job);
$scope.jobId = job.job_id;
$scope.datafeedId = mlJobService.getDatafeedId(job.job_id);
$scope.start = '';
$scope.end = '';
let lastTime = '';
if (job.data_counts && job.data_counts.latest_record_timestamp) {
const time = moment(job.data_counts.latest_record_timestamp);
lastTime = time.format('YYYY-MM-DD HH:mm:ss');
}
$scope.isNew = (job.data_counts && job.data_counts.input_record_count > 0) ? false : true;
$scope.startAtBeginningOfDataLabel = i18n('xpack.ml.jobTimePickerModal.startAtBeginningOfDataLabel', {
defaultMessage: 'Start at beginning of data'
});
$scope.continueFromLastTime = i18n('xpack.ml.jobTimePickerModal.continueFromLastTimeLabel', {
defaultMessage: 'Continue from {lastTime}',
values: { lastTime }
});
$scope.startNowLabel = i18n('xpack.ml.jobTimePickerModal.startNowLabel', {
defaultMessage: 'Start now'
});
$scope.continueFromNowLabel = i18n('xpack.ml.jobTimePickerModal.continueFromNowLabel', {
defaultMessage: 'Continue from now'
});
$scope.specifyStartTimeLabel = i18n('xpack.ml.jobTimePickerModal.specifyStartTimeLabel', {
defaultMessage: 'Specify start time'
});
$scope.continueFromSpecifiedTimeLabel = i18n('xpack.ml.jobTimePickerModal.continueFromSpecifiedTimeLabel', {
defaultMessage: 'Continue from specified time'
});
$scope.ui = {
lastTime: lastTime,
startDateText: '',
startRadio: '1',
endDateText: '',
endRadio: '1',
timepicker: {
from: '',
to: moment()
},
setStartRadio: function (i) {
$scope.ui.startRadio = i;
},
createWatch: false
};
function extractForm() {
if ($scope.ui.startRadio === '0') {
$scope.start = 'now';
}
else if ($scope.ui.startRadio === '1') {
$scope.start = '0';
}
else if ($scope.ui.startRadio === '2') {
$scope.start = moment($scope.ui.timepicker.from).unix() * 1000;
}
if ($scope.ui.endRadio === '0') {
$scope.end = undefined;
} else if ($scope.ui.endRadio === '1') {
$scope.end = moment($scope.ui.timepicker.to).unix() * 1000;
}
}
$scope.save = function () {
$scope.saveLock = true;
extractForm();
let doStartCalled = false;
// in 10s call the function to start the datafeed.
// if the job has already opened and doStart has already been called, nothing will happen.
// However, if the job is still waiting to be opened, the datafeed can be started anyway.
window.setTimeout(doStart, 10000);
// Attempt to open the job first.
// If it's already open, ignore the 409 error
mlJobService.openJob($scope.jobId)
.then(() => {
doStart();
})
.catch((resp) => {
const couldNotOpenJobErrorMessage = i18n('xpack.ml.jobTimePickerModal.couldNotOpenJobErrorMessage', {
defaultMessage: 'Could not open {jobId}',
values: { jobId: $scope.jobId }
});
if (resp.statusCode === 409) {
doStart();
} else {
if (resp.statusCode === 500) {
if (doStartCalled === false) {
// doStart hasn't been called yet, this 500 has returned before 10s,
// so it's not due to a timeout
msgs.error(couldNotOpenJobErrorMessage, resp);
}
} else {
// console.log(resp);
msgs.error(couldNotOpenJobErrorMessage, resp);
}
$scope.saveLock = false;
}
});
// start the datafeed
function doStart() {
if (doStartCalled === false) {
doStartCalled = true;
mlJobService.startDatafeed($scope.datafeedId, $scope.jobId, $scope.start, $scope.end)
.then(() => {
$rootScope.$broadcast('jobsUpdated');
if ($scope.ui.createWatch) {
$rootScope.$broadcast('openCreateWatchWindow', job);
}
})
.catch(() => {
$scope.saveLock = false;
});
}
}
$modalInstance.close();
window.setTimeout(() => {
$rootScope.$broadcast('jobsUpdated');
}, 500);
};
$scope.cancel = function () {
$modalInstance.close();
};
});

View file

@ -8,7 +8,7 @@
import { timefilter } from 'ui/timefilter';
import { ml } from 'plugins/ml/services/ml_api_service';
import { loadFullJob, filterJobs } from '../utils';
import { loadFullJob, filterJobs, checkForAutoStartDatafeed } from '../utils';
import { JobsList } from '../jobs_list';
import { JobDetails } from '../job_details';
import { JobFilterBar } from '../job_filter_bar';
@ -85,6 +85,12 @@ export class JobsListView extends Component {
this.initAutoRefresh();
this.initAutoRefreshUpdate();
// check to see if we need to open the start datafeed modal
// after the page has rendered. This will happen if the user
// has just created a job in the advanced wizard and selected to
// start the datafeed now.
this.openAutoStartDatafeedModal();
}
componentWillUnmount() {
@ -136,6 +142,13 @@ export class JobsListView extends Component {
clearInterval(jobsRefreshInterval);
}
openAutoStartDatafeedModal() {
const job = checkForAutoStartDatafeed();
if (job !== undefined) {
this.showStartDatafeedModal([job]);
}
}
toggleRow = (jobId) => {
if (this.state.itemIdToExpandedRowMap[jobId]) {
const itemIdToExpandedRowMap = { ...this.state.itemIdToExpandedRowMap };

View file

@ -251,6 +251,24 @@ export function filterJobs(jobs, clauses) {
return filteredJobs;
}
// check to see if a job has been stored in mlJobService.currentJob
// if it has, return an object with the minimum properties needed for the
// start datafeed modal.
export function checkForAutoStartDatafeed() {
const job = mlJobService.currentJob;
if (job !== undefined) {
mlJobService.currentJob = undefined;
const hasDatafeed = (typeof job.datafeed_config === 'object' && Object.keys(job.datafeed_config).length > 0);
const datafeedId = hasDatafeed ? job.datafeed_config.datafeed_id : '';
return {
id: job.job_id,
hasDatafeed,
latestTimestampSortValue: 0,
datafeedId,
};
}
}
function stringMatch(str, substr) {
return (
(typeof str === 'string' && typeof substr === 'string') &&

View file

@ -11,5 +11,4 @@ import './detectors_list_directive';
import './save_status_modal';
import './field_select_directive';
import 'plugins/ml/components/job_group_select';
import 'plugins/ml/jobs/components/job_timepicker_modal';
import './enable_model_plot_callout';

View file

@ -78,7 +78,6 @@ module.controller('MlNewJob',
$location,
$modal,
Private,
mlDatafeedService,
mlConfirmModalService,
i18n) {
@ -622,7 +621,8 @@ module.controller('MlNewJob',
if (datafeedConfig) {
// open job successful, create a new datafeed
mlJobService.saveNewDatafeed(datafeedConfig, jobId)
.then(() => {
.then((resp) => {
datafeedConfig.datafeed_id = resp.datafeed_id;
$scope.saveLock = false;
})
.catch((resp) => {
@ -1375,7 +1375,7 @@ module.controller('MlNewJob',
return {
pscope: $scope,
openDatafeed: function () {
mlDatafeedService.openJobTimepickerWindow($scope.job);
mlJobService.currentJob = $scope.job;
}
};
}

View file

@ -24,6 +24,11 @@ let datafeedIds = {};
class JobService {
constructor() {
// currentJob -> used to pass a job object between the job management page and
// and the advanced wizard.
// if populated when loading the advanced wizard, the job is used for cloning.
// if populated when loading the job management page, the start datafeed modal
// is automatically opened.
this.currentJob = undefined;
this.jobs = [];