Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions x-pack/plugins/watcher/common/constants/error_codes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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.
*/

export const ERROR_CODES = {

// Property missing on object
ERR_PROP_MISSING: 'ERR_PROP_MISSING',
};
1 change: 1 addition & 0 deletions x-pack/plugins/watcher/common/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export { WATCH_STATE_COMMENTS } from './watch_state_comments';
export { WATCH_HISTORY } from './watch_history';
export { WATCH_STATES } from './watch_states';
export { WATCH_TYPES } from './watch_types';
export { ERROR_CODES } from './error_codes';
5 changes: 4 additions & 1 deletion x-pack/plugins/watcher/public/models/action/email_action.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export class EmailAction extends BaseAction {
Object.assign(result, {
to: this.to,
subject: this.subject,
body: this.body
body: this.body,
email: {
to: this.to.length ? this.to : undefined,
}
});

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ export class LoggingAction extends BaseAction {

get upstreamJson() {
const result = super.upstreamJson;
const text = !!this.text.trim() ? this.text : undefined;

Object.assign(result, {
text: this.text
text,
logging: {
text,
}
});

return result;
Expand Down
28 changes: 26 additions & 2 deletions x-pack/plugins/watcher/public/models/action/slack_action.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,36 @@ export class SlackAction extends BaseAction {
this.text = props.text;
}

validate() {
const errors = [];

if (!this.to.length) {
errors.push({
message: i18n.translate('xpack.watcher.sections.watchEdit.json.warningPossibleInvalidSlackAction.description', {
defaultMessage: `You are saving a watch with a "Slack" Action but you haven't defined a "to" field.
Unless you have specified a Slack message_default "to" property in your Elasticsearch settings,
this will result in an invalid watch.`
})
});
}

return { errors: errors.length ? errors : null };
}

get upstreamJson() {
const result = super.upstreamJson;

const message = this.text || this.to.length
? {
text: this.text,
to: this.to.length ? this.to : undefined
}
: undefined;
Object.assign(result, {
to: this.to,
text: this.text
text: this.text,
slack: {
message
}
});

return result;
Expand Down
47 changes: 47 additions & 0 deletions x-pack/plugins/watcher/public/models/watch/base_watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export class BaseWatch {
remove(this.actions, action);
}

resetActions = () => {
this.actions = [];
};

get displayName() {
if (this.isNew) {
return i18n.translate('xpack.watcher.models.baseWatch.displayName', {
Expand Down Expand Up @@ -132,6 +136,49 @@ export class BaseWatch {
return isEqual(cleanWatch, cleanOtherWatch);
}

/**
* Client validation of the Watch.
* Currently we are *only* validating the Watch "Actions"
*/
validate() {

// Get the errors from each watch action
const actionsErrors = this.actions.reduce((actionsErrors, action) => {
if (action.validate) {
const { errors } = action.validate();
if (!errors) {
return actionsErrors;
}
return [...actionsErrors, ...errors];
}
return actionsErrors;
}, []);

if (!actionsErrors.length) {
return { warning: null };
}

// Concatenate their message
const errorActionsFragment = actionsErrors.reduce((message, error) => (
!!message
? `${message}, ${error.message}`
: error.message
), '');

// We are not doing any *blocking* validation in the client,
// so for now we return the errors as a warning
return {
warning: {
message: i18n.translate('xpack.watcher.models.baseWatch.invalidWatchWarningMessageText', {
defaultMessage: 'Warning: {errorActionsFragment} Are you sure you want to save the watch in its current state?',
values: {
errorActionsFragment,
}
})
}
};
}

static typeName = i18n.translate('xpack.watcher.models.baseWatch.typeName', {
defaultMessage: 'Watch',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import '../watch_edit_execute_detail';
import '../watch_edit_actions_execute_summary';
import '../watch_edit_watch_execute_summary';
import 'plugins/watcher/services/license';
import { ACTION_TYPES } from '../../../../../common/constants';

const app = uiModules.get('xpack/watcher');

Expand Down Expand Up @@ -100,14 +101,16 @@ app.directive('jsonWatchEdit', function ($injector, i18n) {
}

onWatchSave = () => {
this.createActionsForWatch(this.watch);

if (!this.watch.isNew) {
return this.saveWatch();
return this.validateWatch();
}

return this.isExistingWatch()
.then(existingWatch => {
if (!existingWatch) {
return this.saveWatch();
return this.validateWatch();
}

const confirmModalOptions = {
Expand Down Expand Up @@ -152,6 +155,23 @@ app.directive('jsonWatchEdit', function ($injector, i18n) {
});
}

validateWatch = () => {
const { warning } = this.watch.validate();

if (!warning) {
return this.saveWatch();
}

const confirmModalOptions = {
onConfirm: this.saveWatch,
confirmButtonText: i18n('xpack.watcher.sections.watchEdit.json.watchErrorsWarning.confirmSaveWatch', {
defaultMessage: 'Yes',
}),
};

return confirmModal(warning.message, confirmModalOptions);
}

saveWatch = () => {
return watchService.saveWatch(this.watch)
.then(() => {
Expand Down Expand Up @@ -211,6 +231,60 @@ app.directive('jsonWatchEdit', function ($injector, i18n) {
// dirtyPrompt.deregister();
kbnUrl.change('/management/elasticsearch/watcher/watches', {});
}

/**
* Actions instances are not automatically added to the Watch _actions_ Array
* when we add them in the Json editor.
* This method takes takes care of it.
*
* @param watchModel Watch instance
* @return Watch instance
*/
createActionsForWatch(watchInstance) {
watchInstance.resetActions();

let action;
let type;
let actionProps;

Object.keys(watchInstance.watch.actions).forEach((k) => {
action = watchInstance.watch.actions[k];
type = this.getTypeFromAction(action);
actionProps = this.getPropsFromAction(type, action);

watchInstance.createAction(type, actionProps);
});

return watchInstance;
}

/**
* Get the type from an action where a key defines its type.
* eg: { email: { ... } } | { slack: { ... } }
*
* @param action A raw action object
* @return {string} The action type
*/
getTypeFromAction(action) {
const actionKeys = Object.keys(action);
let type;

Object.keys(ACTION_TYPES).forEach((k) => {
if (actionKeys.includes(ACTION_TYPES[k])) {
type = ACTION_TYPES[k];
}
});

return type ? type : ACTION_TYPES.UNKNOWN;
}

getPropsFromAction(type, action) {
if (type === ACTION_TYPES.SLACK) {
// Slack action has its props inside the "message" object
return action[type].message;
}
return action[type];
}
}
};
});
108 changes: 0 additions & 108 deletions x-pack/plugins/watcher/server/models/action/__tests__/action.js

This file was deleted.

Loading