-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Notification Service #19236
Add Notification Service #19236
Conversation
8f8e063
to
2d62a71
Compare
💔 Build Failed |
Jenkins test this Advanced Setting UI test failure and map server test failure. |
💚 Build Succeeded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What beautiful code @pickypg! LGTM! Thanks for setting us off in the right direction.
* Invokes plugin modules to instantiate the Monitoring plugin for Kibana | ||
* | ||
* @param kibana {Object} Kibana plugin instance | ||
* @return {Object} Monitoring UI Kibana plugin object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should Monitoring => Notifications ?
*/ | ||
export class EmailAction extends Action { | ||
|
||
constructor({ server, options = { }, defaults = { }, _nodemailer = nodemailer }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Options and defaults should be mutually exclusive, right? Defaults can be overridden when triggering a new email action, but options can't, and that is the difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. I should have added docs for the parameters. :) Will fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also removed the default for options
since that means the server isn't defined.
return null; | ||
} | ||
|
||
export async function sendNotification(server, notificationService, actionId, data, reply, { _checkForErrors = checkForErrors } = { }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is exposing _checkForErrors only because of tests? I think there is a way, perhaps if you put it into it's own file, that you can mock it so you don't have to expose it here just for testing purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I am not used to Jest yet, so I did not honestly consider mocking the import. I'll swap that around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up not changing this and instead documented the parameter's purpose (for tests). It's handy to control that function instead of having to mock all of the behaviors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which ... now that I typed it and reread it, I could do by mocking the import.
if (error === null) { | ||
return action.performAction(data) | ||
.then(result => reply(result.toJson())) | ||
.catch(err => reply(wrap(err))); // by API definition, this should never hapepn as performAction isn't allow to throw errrors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hapepn = happen
* | ||
* @returns {Object|undefined} The error response, or {@code undefined} if no error. | ||
*/ | ||
getError() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class looks so clean! I like that you expose the inner variables as functions rather than leaving them to be directly accessed. That was something I was going back and forth on with my panel actions/embeddable stuff. Any particular reason you like this approach best? I don't think we are very consistent about it. Just curious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
I have been working with Typescript recently and it feels more appropriate to have a defined object rather than a bunch of arbitrary properties for a contract like this where some things are inferred. It also enables any future Action
s to extend ActionResult
rather than trying to figure out how to make a custom object that matches all of the same fields and their behavior (e.g., overriding isOk
).
In terms of this code, even I am somewhat inconsistent. The missing fields response is a plain Javascript Object
with a predictable structure. I thought about making a class out of it, but it doesn't need one because nothing is inferred or even dynamic about it -- it just needs a strict interface definition, which Typescript should bring us in pretty short order. Hopefully we'll develop better collective habits once we are able to embrace Typescript within the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can still override properties without making getters (this.isOk = mycustomFunc in the super class), and I think you can still use a typescript interface to define variables as well as functions expected.
But last night I thought of a reason to prefer using getter functions - to give a place where you could put deprecation warnings if you ever wanted to get rid of some variables! At least that works well for a class that acts an a pluggable API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.isOk = mycustomFunc
that's assuming isOk
wasn't just ok
as a field though. It's the whole concept of encapsulation coming from standard Object Oriented development. But I also like your explanation even more.
* Returns mode of the license (basic, gold etc.). This is the "effective" type of the license. | ||
* @returns {string|undefined} | ||
*/ | ||
getMode() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different from type, above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TL;DR It's generally the same thing as type
, but it's the one that you should check (same as isOneOf
does above in this class).
mode
is the operational mode that ES has enabled (the license type
s we're used to). Technically it can be different from type
, but in general they're the exact same value. This comes back from GET /_xpack
, which xpack_main
uses as opposed to GET /_xpack/license
, which reports the mode / type as the same value.
💚 Build Succeeded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Have a look at the markdown -> html comment. Not sure about that, or what effect it has on email clients to send html emails that aren't actually html...
bcc: notification.bcc, | ||
// email content | ||
subject: notification.subject, | ||
html: notification.markdown, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting html
to a markdown
seems incorrect. Is this intentional? Seems like you'd want to convert markdown -> html here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My plan was that we would evolve the Markdown support to be rendered as HTML, but I did not want to focus on that for now since it meant more complexity that we don't need yet.
Enabling it does provide a lot of potential benefits, but it also creates some interesting problems that I wanted to push back on. Namely, if you include image attachments I suspect that many people will want to include them in the body of the email and I didn't want to box us out of something by overstepping here.
const attachments = []; | ||
|
||
if (markdown) { | ||
attachments.push({ text: markdown }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should send raw markdown here or convert to HTML. Similar to my comment in the email action. I honestly prefer raw markdown, so I'm OK with this. Just wanted to point out that we may want to support prettifying it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slack interprets Markdown on its own, so in this case I would not touch it.
This adds a notification service to Kibana that can be used to send asynchronous notifications, such as sending email and Slack messages, which are intended to be configured via a combination of the `kibana.yml` and Kibana keystore. Once configured, the actions are automatically added to the notification service and can be invoked via the server using the `notificationService` singleton or HTTP to send it directly. See the included README for more details.
844eff1
to
d76ba5e
Compare
💚 Build Succeeded |
This adds a notification service to Kibana that can be used to send asynchronous notifications, such as sending email and Slack messages, which are intended to be configured via a combination of the `kibana.yml` and Kibana keystore. Once configured, the actions are automatically added to the notification service and can be invoked via the server using the `notificationService` singleton or HTTP to send it directly. See the included README for more details.
6.x/6.4: e6a88e0 |
Originally added in elastic#19236 as part of the notification service, however it's no longer used. Signed-off-by: Tyler Smalley <[email protected]>
Originally added in #19236 as part of the notification service, however it's no longer used. Signed-off-by: Tyler Smalley <[email protected]>
Originally added in elastic#19236 as part of the notification service, however it's no longer used. Signed-off-by: Tyler Smalley <[email protected]>
Originally added in #19236 as part of the notification service, however it's no longer used. Signed-off-by: Tyler Smalley <[email protected]>
This adds a notification service to Kibana that can be used to send
asynchronous notifications, such as sending email and Slack messages,
which are intended to be configured via a combination of the
kibana.yml
and Kibana keystore.Once configured, the actions are automatically added to the notification
service and can be invoked via the server using the
notificationService
singleton or HTTP to send it directly. See the included README for more
details.
NOTE: This feature is currently experimental.