diff --git a/ui/package-lock.json b/ui/package-lock.json
index 6a779de83..b3de69e77 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -202,14 +202,6 @@
}
}
},
- "add-dom-event-listener": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.0.2.tgz",
- "integrity": "sha1-j67SxBAIchzxEdodMNmVuFvkK+0=",
- "requires": {
- "object-assign": "4.1.1"
- }
- },
"address": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz",
@@ -2322,24 +2314,11 @@
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz",
"integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ=="
},
- "component-classes": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz",
- "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=",
- "requires": {
- "component-indexof": "0.0.3"
- }
- },
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
- "component-indexof": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz",
- "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ="
- },
"compressible": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz",
@@ -2625,15 +2604,6 @@
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
},
- "css-animation": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.4.1.tgz",
- "integrity": "sha1-W4gTEl3g+7uwu+G0cq6EIhRpt6g=",
- "requires": {
- "babel-runtime": "6.26.0",
- "component-classes": "1.2.6"
- }
- },
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -3104,11 +3074,6 @@
"esutils": "2.0.2"
}
},
- "dom-align": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.8.0.tgz",
- "integrity": "sha512-B85D4ef2Gj5lw0rK0KM2+D5/pH7yqNxg2mB+E8uzFaolpm7RQmsxEfjyEuNiF8UBBkffumYDeKRzTzc3LePP+w=="
- },
"dom-converter": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz",
@@ -6949,11 +6914,6 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
},
- "lodash._getnative": {
- "version": "3.9.1",
- "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
- "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
- },
"lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -7002,11 +6962,6 @@
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
"dev": true
},
- "lodash.isarguments": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
- "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
- },
"lodash.isarray": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz",
@@ -7022,23 +6977,6 @@
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0="
},
- "lodash.keys": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
- "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
- "requires": {
- "lodash._getnative": "3.9.1",
- "lodash.isarguments": "3.1.0",
- "lodash.isarray": "3.0.4"
- },
- "dependencies": {
- "lodash.isarray": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
- "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
- }
- }
- },
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -9811,77 +9749,6 @@
}
}
},
- "rc-align": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.3.tgz",
- "integrity": "sha512-h5KgyB5IXYR7iKpYFcMr54cuQ2eozPCZ11kbXPG5+6CWvmyJ+c0R/yjndVndiNk2G3MKcTMbJNdDv5DIckLAxQ==",
- "requires": {
- "babel-runtime": "6.26.0",
- "dom-align": "1.8.0",
- "prop-types": "15.6.2",
- "rc-util": "4.5.1"
- }
- },
- "rc-animate": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.4.4.tgz",
- "integrity": "sha512-DjJLTUQj7XKKcuS8cczN0uOLfuSmgrVXFGieP1SZc87xUUTFGh8B/KjNmEtlfvxkSrSuVfb2rrEPER4SqKUtEA==",
- "requires": {
- "babel-runtime": "6.26.0",
- "css-animation": "1.4.1",
- "prop-types": "15.6.2"
- }
- },
- "rc-calendar": {
- "version": "9.7.0",
- "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.7.0.tgz",
- "integrity": "sha512-067i3TC0H/6N6ZIhtbe9o/+F955n9nujNxn6Hoi6dJNr0LXc6F7305EI8N9k3zycx9JAliFQ1LF+MeFQwWRwpw==",
- "requires": {
- "babel-runtime": "6.26.0",
- "classnames": "2.2.6",
- "create-react-class": "15.6.3",
- "moment": "2.22.2",
- "prop-types": "15.6.2",
- "rc-trigger": "2.5.4",
- "rc-util": "4.5.1"
- }
- },
- "rc-time-picker": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.4.0.tgz",
- "integrity": "sha512-BgF0Fu/d36AK0h8jYBa01VWCm5vHWtYCh4DXBQhNazPLSH9hMP6JHLMJPSYMJ9jKttdE18O+F3j0mVQCL8JpDg==",
- "requires": {
- "babel-runtime": "6.26.0",
- "classnames": "2.2.6",
- "moment": "2.22.2",
- "prop-types": "15.6.2",
- "rc-trigger": "2.5.4"
- }
- },
- "rc-trigger": {
- "version": "2.5.4",
- "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.5.4.tgz",
- "integrity": "sha512-clgXOdazDW2qg4vTZSAExpvOuojPNuMoamG+SxAm5Ih+rpVcrtEiDlDZWY4yUHyfEWJZBzgbrr4np/z2FK6RfA==",
- "requires": {
- "babel-runtime": "6.26.0",
- "classnames": "2.2.6",
- "prop-types": "15.6.2",
- "rc-align": "2.4.3",
- "rc-animate": "2.4.4",
- "rc-util": "4.5.1"
- }
- },
- "rc-util": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.5.1.tgz",
- "integrity": "sha512-PdCmHyBBodZdw6Oaikt0l+/R79IcRXpYkTrqD/Rbl4ZdoOi61t5TtEe40Q+A7rkWG5U1xjcN+h8j9H6GdtnICw==",
- "requires": {
- "add-dom-event-listener": "1.0.2",
- "babel-runtime": "6.26.0",
- "prop-types": "15.6.2",
- "shallowequal": "0.2.2"
- }
- },
"react": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
@@ -9913,6 +9780,28 @@
"section-iterator": "2.0.0"
}
},
+ "react-datepicker": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-1.6.0.tgz",
+ "integrity": "sha512-wfFfw3Tn+CCTtP7PPPhSAfkfVT3UTifFb8BmuhtwWKK3g4S83EEPRQE18XFtxd22dKGqp336NVtDTTyUJ1p9+g==",
+ "requires": {
+ "classnames": "2.2.6",
+ "prop-types": "15.6.2",
+ "react-onclickoutside": "6.7.1",
+ "react-popper": "0.9.5"
+ },
+ "dependencies": {
+ "react-popper": {
+ "version": "0.9.5",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-0.9.5.tgz",
+ "integrity": "sha1-AqJO8+7DOvnlToNYq3DrDjMe3QU=",
+ "requires": {
+ "popper.js": "1.14.4",
+ "prop-types": "15.6.2"
+ }
+ }
+ }
+ },
"react-dev-utils": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.1.tgz",
@@ -11006,14 +10895,6 @@
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.0.0.tgz",
"integrity": "sha1-UI0YOLPeWQq4dXsBGyXkMJAJRfc="
},
- "shallowequal": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",
- "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=",
- "requires": {
- "lodash.keys": "3.1.2"
- }
- },
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
diff --git a/ui/package.json b/ui/package.json
index 333c02240..f742a699e 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -25,10 +25,9 @@
"prop-types": "15.6.2",
"qs": "6.5.2",
"raven-js": "3.26.4",
- "rc-calendar": "9.7.0",
- "rc-time-picker": "3.4.0",
"react": "16.4.2",
"react-autosuggest": "9.3.4",
+ "react-datepicker": "1.6.0",
"react-dom": "16.4.2",
"react-highlighter": "0.4.2",
"react-input-range": "1.3.0",
diff --git a/ui/src/Components/SilenceModal/DateTimeSelect/Duration.js b/ui/src/Components/SilenceModal/DateTimeSelect/Duration.js
new file mode 100644
index 000000000..5208b79aa
--- /dev/null
+++ b/ui/src/Components/SilenceModal/DateTimeSelect/Duration.js
@@ -0,0 +1,66 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import { observer } from "mobx-react";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faAngleUp } from "@fortawesome/free-solid-svg-icons/faAngleUp";
+import { faAngleDown } from "@fortawesome/free-solid-svg-icons/faAngleDown";
+
+const Duration = observer(
+ class Duration extends Component {
+ static propTypes = {
+ value: PropTypes.number.isRequired,
+ label: PropTypes.string,
+ onInc: PropTypes.func.isRequired,
+ onDec: PropTypes.func.isRequired
+ };
+
+ render() {
+ const { value, label, onInc, onDec } = this.props;
+
+ return (
+
+
+
+ |
+
+
+
+ |
+ |
+
+
+
+ {value}
+ |
+
+ {label ? (
+ {label}
+ ) : null}
+ |
+
+
+ |
+
+
+
+ |
+ |
+
+
+
+ );
+ }
+ }
+);
+
+export { Duration };
diff --git a/ui/src/Components/SilenceModal/DateTimeSelect/HourMinute.js b/ui/src/Components/SilenceModal/DateTimeSelect/HourMinute.js
new file mode 100644
index 000000000..3a35e1856
--- /dev/null
+++ b/ui/src/Components/SilenceModal/DateTimeSelect/HourMinute.js
@@ -0,0 +1,81 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import { observer } from "mobx-react";
+
+import moment from "moment";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faAngleUp } from "@fortawesome/free-solid-svg-icons/faAngleUp";
+import { faAngleDown } from "@fortawesome/free-solid-svg-icons/faAngleDown";
+
+const IconTd = ({ icon, onClick }) => (
+
+
+
+
+ |
+);
+IconTd.propTypes = {
+ icon: PropTypes.object.isRequired,
+ onClick: PropTypes.func.isRequired
+};
+
+const HourMinute = observer(
+ class HourMinute extends Component {
+ static propTypes = {
+ dateValue: PropTypes.instanceOf(moment).isRequired,
+ onHourInc: PropTypes.func.isRequired,
+ onHourDec: PropTypes.func.isRequired,
+ onMinuteInc: PropTypes.func.isRequired,
+ onMinuteDec: PropTypes.func.isRequired
+ };
+
+ render() {
+ const {
+ dateValue,
+ onHourInc,
+ onHourDec,
+ onMinuteInc,
+ onMinuteDec
+ } = this.props;
+
+ const hour = dateValue.hour();
+ const minute = dateValue.minute();
+
+ return (
+
+
+
+
+ |
+
+
+
+
+ {hour > 9 ? hour : `0${hour}`}
+ |
+
+ :
+ |
+
+ {minute > 9 ? minute : `0${minute}`}
+ |
+
+
+
+ |
+
+
+
+
+ );
+ }
+ }
+);
+
+export { HourMinute };
diff --git a/ui/src/Components/SilenceModal/DateTimeSelect/index.css b/ui/src/Components/SilenceModal/DateTimeSelect/index.css
new file mode 100644
index 000000000..68f1e2bda
--- /dev/null
+++ b/ui/src/Components/SilenceModal/DateTimeSelect/index.css
@@ -0,0 +1,484 @@
+.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow,
+.react-datepicker__month-read-view--down-arrow,
+.react-datepicker__month-year-read-view--down-arrow {
+ margin-left: -8px;
+ position: absolute; }
+ .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__month-year-read-view--down-arrow, .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before,
+ .react-datepicker__month-read-view--down-arrow::before,
+ .react-datepicker__month-year-read-view--down-arrow::before {
+ box-sizing: content-box;
+ position: absolute;
+ border: 8px solid transparent;
+ height: 0;
+ width: 1px; }
+ .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before,
+ .react-datepicker__month-read-view--down-arrow::before,
+ .react-datepicker__month-year-read-view--down-arrow::before {
+ content: "";
+ z-index: -1;
+ border-width: 8px;
+ left: -8px;
+ border-bottom-color: #dee2e6; }
+
+.react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle {
+ top: 0;
+ margin-top: -8px; }
+ .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle, .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before {
+ border-top: none;
+ border-bottom-color: #fff; }
+ .react-datepicker-popper[data-placement^="bottom"] .react-datepicker__triangle::before {
+ top: -1px;
+ border-bottom-color: #dee2e6; }
+
+.react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow,
+.react-datepicker__month-read-view--down-arrow,
+.react-datepicker__month-year-read-view--down-arrow {
+ bottom: 0;
+ margin-bottom: -8px; }
+ .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle, .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__month-year-read-view--down-arrow, .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before,
+ .react-datepicker__month-read-view--down-arrow::before,
+ .react-datepicker__month-year-read-view--down-arrow::before {
+ border-bottom: none;
+ border-top-color: #fff; }
+ .react-datepicker-popper[data-placement^="top"] .react-datepicker__triangle::before, .react-datepicker__year-read-view--down-arrow::before,
+ .react-datepicker__month-read-view--down-arrow::before,
+ .react-datepicker__month-year-read-view--down-arrow::before {
+ bottom: -1px;
+ border-top-color: #dee2e6; }
+
+.react-datepicker-wrapper {
+ display: inline-block; }
+
+.react-datepicker {
+ font-family: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ font-size: 0.9375rem;
+ background-color: #fff;
+ color: #000;
+ border: 1px solid #dee2e6;
+ border-radius: 0.25rem;
+ display: inline-block;
+ position: relative; }
+
+.react-datepicker--time-only .react-datepicker__triangle {
+ left: 35px; }
+
+.react-datepicker--time-only .react-datepicker__time-container {
+ border-left: 0; }
+
+.react-datepicker--time-only .react-datepicker__time {
+ border-radius: 0.3rem; }
+
+.react-datepicker--time-only .react-datepicker__time-box {
+ border-radius: 0.3rem; }
+
+.react-datepicker__triangle {
+ position: absolute;
+ left: 50px; }
+
+.react-datepicker-popper {
+ z-index: 1; }
+ .react-datepicker-popper[data-placement^="bottom"] {
+ margin-top: 10px; }
+ .react-datepicker-popper[data-placement^="top"] {
+ margin-bottom: 10px; }
+ .react-datepicker-popper[data-placement^="right"] {
+ margin-left: 8px; }
+ .react-datepicker-popper[data-placement^="right"] .react-datepicker__triangle {
+ left: auto;
+ right: 42px; }
+ .react-datepicker-popper[data-placement^="left"] {
+ margin-right: 8px; }
+ .react-datepicker-popper[data-placement^="left"] .react-datepicker__triangle {
+ left: 42px;
+ right: auto; }
+
+.react-datepicker__header {
+ text-align: center;
+ background-color: #fff;
+ border-bottom: 1px solid #dee2e6;
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem;
+ padding-top: 8px;
+ position: relative; }
+ .react-datepicker__header--time {
+ padding-bottom: 8px;
+ padding-left: 5px;
+ padding-right: 5px; }
+
+.react-datepicker__year-dropdown-container--select,
+.react-datepicker__month-dropdown-container--select,
+.react-datepicker__month-year-dropdown-container--select,
+.react-datepicker__year-dropdown-container--scroll,
+.react-datepicker__month-dropdown-container--scroll,
+.react-datepicker__month-year-dropdown-container--scroll {
+ display: inline-block;
+ margin: 0 2px; }
+
+.react-datepicker__current-month,
+.react-datepicker-time__header {
+ margin-top: 0;
+ color: #000;
+ font-weight: bold;
+ font-size: 1.10625rem; }
+
+.react-datepicker-time__header {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden; }
+
+.react-datepicker__navigation {
+ background: none;
+ line-height: 1.7rem;
+ text-align: center;
+ cursor: pointer;
+ position: absolute;
+ top: 10px;
+ width: 0;
+ padding: 0;
+ border: 0.45rem solid transparent;
+ z-index: 1;
+ height: 10px;
+ width: 10px;
+ text-indent: -999em;
+ overflow: hidden; }
+ .react-datepicker__navigation--previous {
+ left: 10px;
+ border-right-color: #95a5a6; }
+ .react-datepicker__navigation--previous:hover {
+ border-right-color: #798d8f; }
+ .react-datepicker__navigation--previous--disabled, .react-datepicker__navigation--previous--disabled:hover {
+ border-right-color: #95a5a6;
+ cursor: default; }
+ .react-datepicker__navigation--next {
+ right: 10px;
+ border-left-color: #95a5a6; }
+ .react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) {
+ right: 80px; }
+ .react-datepicker__navigation--next:hover {
+ border-left-color: #798d8f; }
+ .react-datepicker__navigation--next--disabled, .react-datepicker__navigation--next--disabled:hover {
+ border-left-color: #95a5a6;
+ cursor: default; }
+ .react-datepicker__navigation--years {
+ position: relative;
+ top: 0;
+ display: block;
+ margin-left: auto;
+ margin-right: auto; }
+ .react-datepicker__navigation--years-previous {
+ top: 4px;
+ border-top-color: #95a5a6; }
+ .react-datepicker__navigation--years-previous:hover {
+ border-top-color: #798d8f; }
+ .react-datepicker__navigation--years-upcoming {
+ top: -4px;
+ border-bottom-color: #95a5a6; }
+ .react-datepicker__navigation--years-upcoming:hover {
+ border-bottom-color: #798d8f; }
+
+.react-datepicker__month-container {
+ float: left; }
+
+.react-datepicker__month {
+ margin: 0.4rem;
+ text-align: center; }
+
+.react-datepicker__time-container {
+ float: right;
+ border-left: 1px solid #dee2e6;
+ width: 70px; }
+ .react-datepicker__time-container--with-today-button {
+ display: inline;
+ border: 1px solid #aeaeae;
+ border-radius: 0.3rem;
+ position: absolute;
+ right: -72px;
+ top: 0; }
+ .react-datepicker__time-container .react-datepicker__time {
+ position: relative;
+ background: white; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box {
+ width: 70px;
+ overflow-x: hidden;
+ margin: 0 auto;
+ text-align: center; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list {
+ list-style: none;
+ margin: 0;
+ height: calc(195px + (1.7rem / 2));
+ overflow-y: scroll;
+ padding-right: 30px;
+ width: 100%;
+ box-sizing: content-box; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item {
+ padding: 5px 10px; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item:hover {
+ cursor: pointer;
+ background-color: #fff; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected {
+ background-color: #2C3E50;
+ color: white;
+ font-weight: bold; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--selected:hover {
+ background-color: #2C3E50; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--disabled {
+ color: #95a5a6; }
+ .react-datepicker__time-container .react-datepicker__time .react-datepicker__time-box ul.react-datepicker__time-list li.react-datepicker__time-list-item--disabled:hover {
+ cursor: default;
+ background-color: transparent; }
+
+.react-datepicker__week-number {
+ color: #95a5a6;
+ display: inline-block;
+ width: 1.7rem;
+ line-height: 1.7rem;
+ text-align: center;
+ margin: 0.166rem; }
+ .react-datepicker__week-number.react-datepicker__week-number--clickable {
+ cursor: pointer; }
+ .react-datepicker__week-number.react-datepicker__week-number--clickable:hover {
+ border-radius: 0.25rem;
+ background-color: #fff; }
+
+.react-datepicker__day-names,
+.react-datepicker__week {
+ white-space: nowrap; }
+
+.react-datepicker__day-name,
+.react-datepicker__day,
+.react-datepicker__time-name {
+ color: #000;
+ display: inline-block;
+ width: 1.7rem;
+ line-height: 1.7rem;
+ text-align: center;
+ margin: 0.166rem; }
+
+.react-datepicker__day {
+ cursor: pointer; }
+ .react-datepicker__day:hover {
+ border-radius: 0.25rem;
+ background-color: #fff; }
+ .react-datepicker__day--today {
+ font-weight: bold; }
+ .react-datepicker__day--highlighted {
+ border-radius: 0.25rem;
+ background-color: #95a5a6;
+ color: #fff; }
+ .react-datepicker__day--highlighted:hover {
+ background-color: #87999a; }
+ .react-datepicker__day--highlighted-custom-1 {
+ color: magenta; }
+ .react-datepicker__day--highlighted-custom-2 {
+ color: green; }
+ .react-datepicker__day--selected, .react-datepicker__day--in-selecting-range, .react-datepicker__day--in-range {
+ border-radius: 0.25rem;
+ background-color: #2C3E50;
+ color: #fff; }
+ .react-datepicker__day--selected:hover, .react-datepicker__day--in-selecting-range:hover, .react-datepicker__day--in-range:hover {
+ background-color: #233140; }
+ .react-datepicker__day--keyboard-selected {
+ border-radius: 0.25rem;
+ background-color: #3e5871;
+ color: #fff; }
+ .react-datepicker__day--keyboard-selected:hover {
+ background-color: #233140; }
+ .react-datepicker__day--in-selecting-range:not(.react-datepicker__day--in-range) {
+ background-color: rgba(44, 62, 80, 0.5); }
+ .react-datepicker__month--selecting-range .react-datepicker__day--in-range:not(.react-datepicker__day--in-selecting-range) {
+ background-color: #fff;
+ color: #000; }
+ .react-datepicker__day--disabled {
+ cursor: default;
+ color: #95a5a6; }
+ .react-datepicker__day--disabled:hover {
+ background-color: transparent; }
+
+.react-datepicker__input-container {
+ position: relative;
+ display: inline-block; }
+
+.react-datepicker__year-read-view,
+.react-datepicker__month-read-view,
+.react-datepicker__month-year-read-view {
+ border: 1px solid transparent;
+ border-radius: 0.25rem; }
+ .react-datepicker__year-read-view:hover,
+ .react-datepicker__month-read-view:hover,
+ .react-datepicker__month-year-read-view:hover {
+ cursor: pointer; }
+ .react-datepicker__year-read-view:hover .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__year-read-view:hover .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__month-read-view:hover .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__month-read-view:hover .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__month-year-read-view:hover .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__month-year-read-view:hover .react-datepicker__month-read-view--down-arrow {
+ border-top-color: #798d8f; }
+ .react-datepicker__year-read-view--down-arrow,
+ .react-datepicker__month-read-view--down-arrow,
+ .react-datepicker__month-year-read-view--down-arrow {
+ border-top-color: #95a5a6;
+ float: right;
+ margin-left: 20px;
+ top: 8px;
+ position: relative;
+ border-width: 0.45rem; }
+
+.react-datepicker__year-dropdown,
+.react-datepicker__month-dropdown,
+.react-datepicker__month-year-dropdown {
+ background-color: #fff;
+ position: absolute;
+ width: 50%;
+ left: 25%;
+ top: 30px;
+ z-index: 1;
+ text-align: center;
+ border-radius: 0.25rem;
+ border: 1px solid #dee2e6; }
+ .react-datepicker__year-dropdown:hover,
+ .react-datepicker__month-dropdown:hover,
+ .react-datepicker__month-year-dropdown:hover {
+ cursor: pointer; }
+ .react-datepicker__year-dropdown--scrollable,
+ .react-datepicker__month-dropdown--scrollable,
+ .react-datepicker__month-year-dropdown--scrollable {
+ height: 150px;
+ overflow-y: scroll; }
+
+.react-datepicker__year-option,
+.react-datepicker__month-option,
+.react-datepicker__month-year-option {
+ line-height: 20px;
+ width: 100%;
+ display: block;
+ margin-left: auto;
+ margin-right: auto; }
+ .react-datepicker__year-option:first-of-type,
+ .react-datepicker__month-option:first-of-type,
+ .react-datepicker__month-year-option:first-of-type {
+ border-top-left-radius: 0.25rem;
+ border-top-right-radius: 0.25rem; }
+ .react-datepicker__year-option:last-of-type,
+ .react-datepicker__month-option:last-of-type,
+ .react-datepicker__month-year-option:last-of-type {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ border-bottom-left-radius: 0.25rem;
+ border-bottom-right-radius: 0.25rem; }
+ .react-datepicker__year-option:hover,
+ .react-datepicker__month-option:hover,
+ .react-datepicker__month-year-option:hover {
+ background-color: #95a5a6; }
+ .react-datepicker__year-option:hover .react-datepicker__navigation--years-upcoming,
+ .react-datepicker__month-option:hover .react-datepicker__navigation--years-upcoming,
+ .react-datepicker__month-year-option:hover .react-datepicker__navigation--years-upcoming {
+ border-bottom-color: #798d8f; }
+ .react-datepicker__year-option:hover .react-datepicker__navigation--years-previous,
+ .react-datepicker__month-option:hover .react-datepicker__navigation--years-previous,
+ .react-datepicker__month-year-option:hover .react-datepicker__navigation--years-previous {
+ border-top-color: #798d8f; }
+ .react-datepicker__year-option--selected,
+ .react-datepicker__month-option--selected,
+ .react-datepicker__month-year-option--selected {
+ position: absolute;
+ left: 15px; }
+
+.react-datepicker__close-icon {
+ background-color: transparent;
+ border: 0;
+ cursor: pointer;
+ outline: 0;
+ padding: 0;
+ vertical-align: middle;
+ position: absolute;
+ height: 16px;
+ width: 16px;
+ top: 25%;
+ right: 7px; }
+ .react-datepicker__close-icon::after {
+ background-color: #2C3E50;
+ border-radius: 50%;
+ bottom: 0;
+ box-sizing: border-box;
+ color: #fff;
+ content: "\00d7";
+ cursor: pointer;
+ font-size: 12px;
+ height: 16px;
+ width: 16px;
+ line-height: 1;
+ margin: -8px auto 0;
+ padding: 2px;
+ position: absolute;
+ right: 0px;
+ text-align: center; }
+
+.react-datepicker__today-button {
+ background: #fff;
+ border-top: 1px solid #dee2e6;
+ cursor: pointer;
+ text-align: center;
+ font-weight: bold;
+ padding: 5px 0;
+ clear: left; }
+
+.react-datepicker__portal {
+ position: fixed;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(0, 0, 0, 0.8);
+ left: 0;
+ top: 0;
+ justify-content: center;
+ align-items: center;
+ display: flex;
+ z-index: 2147483647; }
+ .react-datepicker__portal .react-datepicker__day-name,
+ .react-datepicker__portal .react-datepicker__day,
+ .react-datepicker__portal .react-datepicker__time-name {
+ width: 3rem;
+ line-height: 3rem; }
+ @media (max-width: 400px), (max-height: 550px) {
+ .react-datepicker__portal .react-datepicker__day-name,
+ .react-datepicker__portal .react-datepicker__day,
+ .react-datepicker__portal .react-datepicker__time-name {
+ width: 2rem;
+ line-height: 2rem; } }
+ .react-datepicker__portal .react-datepicker__current-month,
+ .react-datepicker__portal .react-datepicker-time__header {
+ font-size: 1.6875rem; }
+ .react-datepicker__portal .react-datepicker__navigation {
+ border: 0.81rem solid transparent; }
+ .react-datepicker__portal .react-datepicker__navigation--previous {
+ border-right-color: #95a5a6; }
+ .react-datepicker__portal .react-datepicker__navigation--previous:hover {
+ border-right-color: #798d8f; }
+ .react-datepicker__portal .react-datepicker__navigation--previous--disabled, .react-datepicker__portal .react-datepicker__navigation--previous--disabled:hover {
+ border-right-color: #95a5a6;
+ cursor: default; }
+ .react-datepicker__portal .react-datepicker__navigation--next {
+ border-left-color: #95a5a6; }
+ .react-datepicker__portal .react-datepicker__navigation--next:hover {
+ border-left-color: #798d8f; }
+ .react-datepicker__portal .react-datepicker__navigation--next--disabled, .react-datepicker__portal .react-datepicker__navigation--next--disabled:hover {
+ border-left-color: #95a5a6;
+ cursor: default; }
+
+.react-datepicker__day:not(.react-datepicker__day--disabled) {
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent; }
+
+.react-datepicker__day:hover:not(.react-datepicker__day--disabled) {
+ border-color: #dee2e6; }
+
+.react-datepicker__today-button {
+ border-bottom-left-radius: 0.25rem;
+ border-bottom-right-radius: 0.25rem; }
diff --git a/ui/src/Components/SilenceModal/DateTimeSelect/index.js b/ui/src/Components/SilenceModal/DateTimeSelect/index.js
new file mode 100644
index 000000000..922d0b2a8
--- /dev/null
+++ b/ui/src/Components/SilenceModal/DateTimeSelect/index.js
@@ -0,0 +1,181 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import { observable, action } from "mobx";
+import { observer } from "mobx-react";
+
+import moment from "moment";
+
+import DatePicker from "react-datepicker";
+
+import { Duration } from "./Duration";
+import { HourMinute } from "./HourMinute";
+
+import "./index.css";
+
+const Tab = ({ title, active, onClick }) => (
+
+
+ {title}
+
+
+);
+Tab.propTypes = {
+ title: PropTypes.node.isRequired,
+ active: PropTypes.bool,
+ onClick: PropTypes.func.isRequired
+};
+
+const TabNames = Object.freeze({
+ Start: "start",
+ End: "end",
+ Duration: "duration"
+});
+
+const TabContentStart = observer(({ silenceFormStore }) => {
+ return (
+
+ {
+ silenceFormStore.data.startsAt = moment(val);
+ silenceFormStore.data.verifyStarEnd();
+ }}
+ />
+ silenceFormStore.data.incStart(60)}
+ onHourDec={() => silenceFormStore.data.decStart(60)}
+ onMinuteInc={() => silenceFormStore.data.incStart(1)}
+ onMinuteDec={() => silenceFormStore.data.decStart(1)}
+ />
+
+ );
+});
+
+const TabContentEnd = observer(({ silenceFormStore }) => {
+ return (
+
+ {
+ silenceFormStore.data.endsAt = moment(val);
+ silenceFormStore.data.verifyStarEnd();
+ }}
+ />
+ silenceFormStore.data.incEnd(60)}
+ onHourDec={() => silenceFormStore.data.decEnd(60)}
+ onMinuteInc={() => silenceFormStore.data.incEnd(1)}
+ onMinuteDec={() => silenceFormStore.data.decEnd(1)}
+ />
+
+ );
+});
+
+const TabContentDuration = observer(({ silenceFormStore }) => {
+ return (
+
+ silenceFormStore.data.incDuration(60 * 24)}
+ onDec={() => silenceFormStore.data.decDuration(60 * 24)}
+ />
+ silenceFormStore.data.incDuration(60)}
+ onDec={() => silenceFormStore.data.decDuration(60)}
+ />
+ silenceFormStore.data.incDuration(1)}
+ onDec={() => silenceFormStore.data.decDuration(1)}
+ />
+
+ );
+});
+TabContentDuration.propTypes = {
+ silenceFormStore: PropTypes.object.isRequired
+};
+
+const DateTimeSelect = observer(
+ class DateTimeSelect extends Component {
+ static propTypes = {
+ silenceFormStore: PropTypes.object.isRequired
+ };
+
+ tab = observable(
+ {
+ current: TabNames.Duration,
+ setStart() {
+ this.current = TabNames.Start;
+ },
+ setEnd() {
+ this.current = TabNames.End;
+ },
+ setDuration() {
+ this.current = TabNames.Duration;
+ }
+ },
+ {
+ setStart: action.bound,
+ setEnd: action.bound,
+ setDuration: action.bound
+ }
+ );
+
+ render() {
+ const { silenceFormStore } = this.props;
+
+ return (
+
+
+
+ {this.tab.current === TabNames.Duration ? (
+
+ ) : null}
+ {this.tab.current === TabNames.Start ? (
+
+ ) : null}
+ {this.tab.current === TabNames.End ? (
+
+ ) : null}
+
+
+ );
+ }
+ }
+);
+
+export { DateTimeSelect };
diff --git a/ui/src/Components/SilenceModal/DateTimeSelect/index.scss b/ui/src/Components/SilenceModal/DateTimeSelect/index.scss
new file mode 100644
index 000000000..babb1a064
--- /dev/null
+++ b/ui/src/Components/SilenceModal/DateTimeSelect/index.scss
@@ -0,0 +1,29 @@
+@import "../../../../node_modules/bootswatch/dist/flatly/variables";
+
+$datepicker__background-color: $white;
+$datepicker__border-color: $gray-300;
+$datepicker__highlighted-color: $secondary;
+$datepicker__muted-color: $gray-600;
+$datepicker__selected-color: $primary;
+$datepicker__text-color: $black;
+$datepicker__header-color: $black;
+$datepicker__navigation-disabled-color: $gray-600;
+$datepicker__font-size: $font-size-base;
+$datepicker__font-family: $font-family-sans-serif;
+$datepicker__border-radius: 0.25rem;
+
+@import "../../../../node_modules/react-datepicker/src/stylesheets/datepicker.scss";
+
+.react-datepicker__day:not(.react-datepicker__day--disabled) {
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+}
+.react-datepicker__day:hover:not(.react-datepicker__day--disabled) {
+ border-color: $datepicker__border-color;
+}
+
+.react-datepicker__today-button {
+ border-bottom-left-radius: $datepicker__border-radius;
+ border-bottom-right-radius: $datepicker__border-radius;
+}
diff --git a/ui/src/Components/SilenceModal/SilenceForm.js b/ui/src/Components/SilenceModal/SilenceForm.js
index f7e5f8751..6685975b0 100644
--- a/ui/src/Components/SilenceModal/SilenceForm.js
+++ b/ui/src/Components/SilenceModal/SilenceForm.js
@@ -14,7 +14,7 @@ import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
import { AlertManagerInput } from "./AlertManagerInput";
import { SilenceMatch } from "./SilenceMatch";
-import { SilenceStartEnd } from "./SilenceStartEnd";
+import { DateTimeSelect } from "./DateTimeSelect";
import { SilencePreview } from "./SilencePreview";
const IconInput = ({ icon, placeholder, value, onChange }) => (
@@ -124,7 +124,7 @@ const SilenceForm = observer(
>
-
+
.rc-calendar-date {
- border: 0;
- color: #fff;
- background-color: #455a64;
-}
-
-.rc-calendar-today .rc-calendar-date {
- border-color: #7b8a8b;
-}
diff --git a/ui/src/Components/SilenceModal/SilenceStartEnd.js b/ui/src/Components/SilenceModal/SilenceStartEnd.js
deleted file mode 100644
index 9fcd43199..000000000
--- a/ui/src/Components/SilenceModal/SilenceStartEnd.js
+++ /dev/null
@@ -1,129 +0,0 @@
-import React, { Component } from "react";
-import PropTypes from "prop-types";
-
-import { observable, action, toJS } from "mobx";
-import { observer } from "mobx-react";
-
-import moment from "moment";
-
-import Picker from "rc-calendar/lib/Picker";
-import RangeCalendar from "rc-calendar/lib/RangeCalendar";
-import "rc-calendar/assets/index.css";
-
-import TimePickerPanel from "rc-time-picker/lib/Panel";
-import "rc-time-picker/assets/index.css";
-
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faCalendarAlt } from "@fortawesome/free-solid-svg-icons/faCalendarAlt";
-
-import "./SilenceStartEnd.css";
-
-function disabledDate(current) {
- if (!current) return false;
-
- const date = moment();
- date.hour(0);
- date.minute(0);
- date.second(0);
- return current.isBefore(date);
-}
-
-function isValidRange(v) {
- return v && v[0] && v[1];
-}
-
-const format = "YYYY-MM-DD HH:mm";
-function formatTimestamp(v) {
- return v ? v.format(format) : "";
-}
-
-const timePickerElement = (
-
-);
-
-const SilenceStartEnd = observer(
- class SilenceStartEnd extends Component {
- static propTypes = {
- silenceFormStore: PropTypes.object.isRequired
- };
-
- data = observable({
- hoverValue: []
- });
-
- onChange = action(value => {
- const { silenceFormStore } = this.props;
-
- if (value && value[0]) {
- silenceFormStore.data.startsAt = value[0];
- }
- if (value && value[1]) {
- silenceFormStore.data.endsAt = value[1];
- }
- });
-
- onHoverChange = action(value => {
- this.data.hoverValue = value;
- });
-
- render() {
- const { silenceFormStore } = this.props;
-
- const now = moment().second(0);
-
- const calendar = (
-
- );
- return (
-
- {({ value }) => {
- return (
-
- );
- }}
-
- );
- }
- }
-);
-
-export { SilenceStartEnd };
diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js
index 60adb6347..6d31b3a06 100644
--- a/ui/src/Stores/SilenceFormStore.js
+++ b/ui/src/Stores/SilenceFormStore.js
@@ -50,20 +50,24 @@ class SilenceFormStore {
endsAt: moment().add(1, "hour"),
comment: "",
author: "",
+
resetProgress() {
this.inProgress = false;
},
+
// append a new empty matcher to the list
addEmptyMatcher() {
let m = NewEmptyMatcher();
this.matchers.push(m);
},
+
deleteMatcher(id) {
// only delete matchers if we have more than 1
if (this.matchers.length > 1) {
this.matchers = this.matchers.filter(m => m.id !== id);
}
},
+
fillMatchersFromGroup(group) {
let matchers = [];
@@ -108,6 +112,40 @@ class SilenceFormStore {
this.matchers = matchers;
},
+
+ verifyStarEnd() {
+ if (this.endsAt.isSameOrBefore(this.startsAt)) {
+ this.endsAt = moment(this.startsAt).add(1, "minutes");
+ }
+ },
+ incStart(minutes) {
+ this.startsAt = moment(this.startsAt).add(minutes, "minutes");
+ this.verifyStarEnd();
+ },
+ decStart(minutes) {
+ this.startsAt = moment(this.startsAt).subtract(minutes, "minutes");
+ this.verifyStarEnd();
+ },
+
+ incEnd(minutes) {
+ this.endsAt = moment(this.endsAt).add(minutes, "minutes");
+ this.verifyStarEnd();
+ },
+ decEnd(minutes) {
+ this.endsAt = moment(this.endsAt).subtract(minutes, "minutes");
+ this.verifyStarEnd();
+ },
+
+ incDuration(minutes) {
+ this.endsAt = moment(this.endsAt).add(minutes, "minutes");
+ },
+ decDuration(minutes) {
+ const newEndsAt = moment(this.endsAt).subtract(minutes, "minutes");
+ if (newEndsAt.isAfter(this.startsAt)) {
+ this.endsAt = newEndsAt;
+ }
+ },
+
get toAlertmanagerPayload() {
const payload = {
matchers: this.matchers.map(m => ({
@@ -132,6 +170,14 @@ class SilenceFormStore {
comment: this.comment
};
return payload;
+ },
+ get toDuration() {
+ const data = {
+ days: this.endsAt.diff(this.startsAt, "days"),
+ hours: this.endsAt.diff(this.startsAt, "hours") % 24,
+ minutes: this.endsAt.diff(this.startsAt, "minutes") % 60
+ };
+ return data;
}
},
{
@@ -139,7 +185,15 @@ class SilenceFormStore {
addEmptyMatcher: action.bound,
deleteMatcher: action.bound,
fillMatchersFromGroup: action.bound,
- toAlertmanagerPayload: computed
+ verifyStarEnd: action.bound,
+ incStart: action.bound,
+ decStart: action.bound,
+ incEnd: action.bound,
+ decEnd: action.bound,
+ incDuration: action.bound,
+ decDuration: action.bound,
+ toAlertmanagerPayload: computed,
+ toDuration: computed
},
{ name: "Silence form store" }
);