diff --git a/ui/src/Components/AlertAck/index.js b/ui/src/Components/AlertAck/index.js index 11e6d64a6..0db2fb741 100644 --- a/ui/src/Components/AlertAck/index.js +++ b/ui/src/Components/AlertAck/index.js @@ -172,6 +172,20 @@ const AlertAck = observer( return; } + let author = + alertStore.settings.values.silenceForm.author !== "" + ? alertStore.settings.values.silenceForm.author + : silenceFormStore.data.author !== "" + ? toJS(silenceFormStore.data.author) + : toJS(alertStore.settings.values.alertAcknowledgement.author); + + if (alertStore.info.authentication.enabled) { + silenceFormStore.data.author = toJS( + alertStore.info.authentication.username + ); + author = alertStore.info.authentication.username; + } + const alertmanagers = Object.entries(group.alertmanagerCount) .filter(([amName, alertCount]) => alertCount > 0) .map(([amName, _]) => amName); @@ -187,11 +201,7 @@ const AlertAck = observer( toJS(group), toJS(clusterMembers), toJS(alertStore.settings.values.alertAcknowledgement.durationSeconds), - alertStore.settings.values.silenceForm.author !== "" - ? alertStore.settings.values.silenceForm.author - : silenceFormStore.data.author !== "" - ? toJS(silenceFormStore.data.author) - : toJS(alertStore.settings.values.alertAcknowledgement.author), + author, toJS(alertStore.settings.values.alertAcknowledgement.commentPrefix) ); this.submitState.pushSilence(clusterName, pendingSilence); diff --git a/ui/src/Components/AlertAck/index.test.js b/ui/src/Components/AlertAck/index.test.js index 4a6020cfd..14f04daa7 100644 --- a/ui/src/Components/AlertAck/index.test.js +++ b/ui/src/Components/AlertAck/index.test.js @@ -189,6 +189,27 @@ describe("", () => { }); }); + it("uses author from authentication info when auth is enabled", () => { + alertStore.info.authentication.enabled = true; + alertStore.info.authentication.username = "auth@example.com"; + alertStore.settings.values.silenceForm.author = "john@example.com"; + alertStore.settings.values.alertAcknowledgement.durationSeconds = 222; + alertStore.settings.values.alertAcknowledgement.author = "me"; + alertStore.settings.values.alertAcknowledgement.commentPrefix = "FOO:"; + MountAndClick(); + expect(JSON.parse(fetch.mock.calls[0][1].body)).toEqual({ + comment: + "FOO: This alert was acknowledged using karma on Tue Feb 01 2000 00:00:00 GMT+0000", + createdBy: "auth@example.com", + endsAt: "2000-02-01T00:03:42.000Z", + matchers: [ + { isRegex: false, name: "alertname", value: "Fake Alert" }, + { isRegex: true, name: "foo", value: "(bar|baz)" } + ], + startsAt: "2000-02-01T00:00:00.000Z" + }); + }); + it("uses author from alertStore if present", () => { alertStore.settings.values.silenceForm.author = "john@example.com"; alertStore.settings.values.alertAcknowledgement.durationSeconds = 222; diff --git a/ui/src/Components/SilenceModal/AuthorInput.js b/ui/src/Components/SilenceModal/AuthorInput.js new file mode 100644 index 000000000..c7a147e9e --- /dev/null +++ b/ui/src/Components/SilenceModal/AuthorInput.js @@ -0,0 +1,59 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faUser } from "@fortawesome/free-solid-svg-icons/faUser"; + +import { AlertStore } from "Stores/AlertStore"; + +const IconInput = ({ + type, + autoComplete, + icon, + placeholder, + value, + onChange, + ...extra +}) => ( +
+
+ + + +
+ +
+); +IconInput.propTypes = { + type: PropTypes.string.isRequired, + autoComplete: PropTypes.string.isRequired, + icon: FontAwesomeIcon.propTypes.icon.isRequired, + placeholder: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + onChange: PropTypes.func +}; + +const AuthenticatedAuthorInput = ({ alertStore }) => ( + +); +AuthenticatedAuthorInput.propTypes = { + alertStore: PropTypes.instanceOf(AlertStore).isRequired +}; + +export { IconInput, AuthenticatedAuthorInput }; diff --git a/ui/src/Components/SilenceModal/SilenceForm.js b/ui/src/Components/SilenceModal/SilenceForm.js index 511f9a8be..e6a72dfe3 100644 --- a/ui/src/Components/SilenceModal/SilenceForm.js +++ b/ui/src/Components/SilenceModal/SilenceForm.js @@ -21,40 +21,7 @@ import { AlertManagerInput } from "./AlertManagerInput"; import { SilenceMatch } from "./SilenceMatch"; import { DateTimeSelect } from "./DateTimeSelect"; import { PayloadPreview } from "./PayloadPreview"; - -const IconInput = ({ - type, - autoComplete, - icon, - placeholder, - value, - onChange -}) => ( -
-
- - - -
- -
-); -IconInput.propTypes = { - type: PropTypes.string.isRequired, - autoComplete: PropTypes.string.isRequired, - icon: FontAwesomeIcon.propTypes.icon.isRequired, - placeholder: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired -}; +import { IconInput, AuthenticatedAuthorInput } from "./AuthorInput"; const SilenceForm = observer( class SilenceForm extends Component { @@ -111,6 +78,10 @@ const SilenceForm = observer( silenceFormStore.data.author = settingsStore.silenceFormConfig.config.author; } + + if (alertStore.info.authentication.enabled) { + silenceFormStore.data.author = alertStore.info.authentication.username; + } }); addMore = action(event => { @@ -177,14 +148,19 @@ const SilenceForm = observer( - + {alertStore.info.authentication.enabled ? ( + + ) : ( + + )} + preview", () => { }); describe(" inputs", () => { + it("author is read-only when info.authentication.enabled is true", () => { + alertStore.info.authentication.enabled = true; + alertStore.info.authentication.username = "auth@example.com"; + const tree = MountedSilenceForm(); + const input = tree.find("input[placeholder='Author']"); + expect(input.props().readOnly).toBe(true); + expect(input.props().value).toBe("auth@example.com"); + expect(silenceFormStore.data.author).toBe("auth@example.com"); + }); + it("default author value comes from Settings store", () => { settingsStore.silenceFormConfig.config.author = "foo@example.com"; const tree = MountedSilenceForm(); diff --git a/ui/src/Stores/AlertStore.js b/ui/src/Stores/AlertStore.js index 610b6e141..9bbffedad 100644 --- a/ui/src/Stores/AlertStore.js +++ b/ui/src/Stores/AlertStore.js @@ -215,6 +215,10 @@ class AlertStore { info = observable( { + authentication: { + enabled: false, + username: "" + }, totalAlerts: 0, version: "unknown", upgradeNeeded: false, @@ -418,7 +422,7 @@ class AlertStore { this.info.upgradeNeeded = true; } // update extra root level keys that are stored under 'info' - for (const key of ["totalAlerts", "version"]) { + for (const key of ["totalAlerts", "version", "authentication"]) { if (this.info[key] !== result[key]) { this.info[key] = result[key]; }