diff --git a/ui/package-lock.json b/ui/package-lock.json
index a0f5956cb..8b0754aaa 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -9671,6 +9671,11 @@
"resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.7.9.tgz",
"integrity": "sha512-JpHQgpB+p3oqZv583xlJakPXgqdIjGBZvngHYcFhlYxTYs0NDZSdoM1FCpU9T2QmqKOEFBVuhhJBMvJzTkF/wQ=="
},
+ "react-onclickoutside": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.7.1.tgz",
+ "integrity": "sha512-p84kBqGaMoa7VYT0vZ/aOYRfJB+gw34yjpda1Z5KeLflg70HipZOT+MXQenEhdkPAABuE2Astq4zEPdMqUQxcg=="
+ },
"react-popper": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.0.0.tgz",
diff --git a/ui/package.json b/ui/package.json
index c9b3f7131..fb1b0e5ee 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -27,6 +27,7 @@
"react-linkify": "^0.2.2",
"react-masonry-infinite": "^1.2.2",
"react-moment": "^0.7.9",
+ "react-onclickoutside": "^6.7.1",
"react-popper": "^1.0.0",
"react-resize-detector": "^3.0.1",
"react-scripts": "1.1.4",
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js
new file mode 100644
index 000000000..49a0b33bc
--- /dev/null
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js
@@ -0,0 +1,128 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+import { action, observable } from "mobx";
+import { observer } from "mobx-react";
+
+import { Manager, Reference, Popper } from "react-popper";
+import onClickOutside from "react-onclickoutside";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faEllipsisV } from "@fortawesome/free-solid-svg-icons/faEllipsisV";
+import { faShareSquare } from "@fortawesome/free-solid-svg-icons/faShareSquare";
+
+import { FormatAPIFilterQuery } from "Stores/AlertStore";
+import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query";
+
+const MenuContent = onClickOutside(
+ ({ popperPlacement, popperRef, popperStyle, group, afterClick }) => {
+ let groupFilters = Object.keys(group.labels).map(name =>
+ FormatQuery(name, QueryOperators.Equal, group.labels[name])
+ );
+ groupFilters.push(
+ FormatQuery(StaticLabels.Receiver, QueryOperators.Equal, group.receiver)
+ );
+ const groupLink = `?${FormatAPIFilterQuery(groupFilters)}`;
+
+ return (
+
+ );
+ }
+);
+MenuContent.propTypes = {
+ popperPlacement: PropTypes.string,
+ popperRef: PropTypes.func,
+ popperStyle: PropTypes.object,
+ group: PropTypes.object.isRequired,
+ afterClick: PropTypes.func.isRequired
+};
+
+const GroupMenu = observer(
+ class GroupMenu extends Component {
+ static propTypes = {
+ group: PropTypes.object.isRequired
+ };
+
+ collapse = observable(
+ {
+ value: true,
+ toggle() {
+ this.value = !this.value;
+ },
+ hide() {
+ this.value = true;
+ }
+ },
+ { toggle: action.bound, hide: action.bound },
+ { name: "Alert group menu toggle" }
+ );
+
+ handleClickOutside = action(event => {
+ this.collapse.hide();
+ });
+
+ render() {
+ const { group } = this.props;
+
+ return (
+
+
+ {({ ref }) => (
+
+
+
+ )}
+
+
+ {this.collapse.value
+ ? ({ placement, ref, style }) =>
+ : ({ placement, ref, style }) => (
+
+ )}
+
+
+ );
+ }
+ }
+);
+
+export { GroupMenu };
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js
index e619889fd..f3e13cce7 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js
@@ -4,60 +4,43 @@ import PropTypes from "prop-types";
import { observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faShareSquare } from "@fortawesome/free-solid-svg-icons/faShareSquare";
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
-import { FormatAPIFilterQuery } from "Stores/AlertStore";
-import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query";
import { FilteringLabel } from "Components/Labels/FilteringLabel";
import { FilteringCounterBadge } from "Components/Labels/FilteringCounterBadge";
+import { GroupMenu } from "./GroupMenu";
const GroupHeader = observer(
class GroupHeader extends Component {
static propTypes = {
collapseStore: PropTypes.object.isRequired,
- labels: PropTypes.object.isRequired,
- receiver: PropTypes.string.isRequired,
- stateCount: PropTypes.object.isRequired
+ group: PropTypes.object.isRequired
};
render() {
- const { collapseStore, labels, receiver, stateCount } = this.props;
-
- let groupFilters = Object.keys(labels).map(name =>
- FormatQuery(name, QueryOperators.Equal, labels[name])
- );
- groupFilters.push(
- FormatQuery(StaticLabels.Receiver, QueryOperators.Equal, receiver)
- );
- const groupLink = `?${FormatAPIFilterQuery(groupFilters)}`;
+ const { collapseStore, group } = this.props;
return (
-
-
-
+
+
+
- {Object.keys(labels).map(name => (
-
+ {Object.keys(group.labels).map(name => (
+
))}
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
index 038f5ec56..653f4f59a 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
@@ -144,12 +144,7 @@ const AlertGroup = observer(
-
+
{this.collapse.value ? null : (
{group.alerts
diff --git a/ui/src/Components/NavBar/FilterInput/History.js b/ui/src/Components/NavBar/FilterInput/History.js
index 98135c87d..fe6ee961a 100644
--- a/ui/src/Components/NavBar/FilterInput/History.js
+++ b/ui/src/Components/NavBar/FilterInput/History.js
@@ -6,6 +6,7 @@ import { observer } from "mobx-react";
import { localStored } from "mobx-stored";
import { Manager, Reference, Popper } from "react-popper";
+import onClickOutside from "react-onclickoutside";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown";
@@ -28,49 +29,51 @@ function reduceFilter(filter) {
};
}
-const HistoryMenu = ({
- popperPlacement,
- popperRef,
- popperStyle,
- filters,
- alertStore,
- afterClick
-}) => {
- return (
-
- {filters.length === 0 ? (
-
Empty
- ) : (
- filters.map(historyFilters => (
-
- ))
- )}
-
- );
-};
+const HistoryMenu = onClickOutside(
+ ({
+ popperPlacement,
+ popperRef,
+ popperStyle,
+ filters,
+ alertStore,
+ afterClick
+ }) => {
+ return (
+
+ {filters.length === 0 ? (
+
Empty
+ ) : (
+ filters.map(historyFilters => (
+
+ ))
+ )}
+
+ );
+ }
+);
HistoryMenu.propTypes = {
popperPlacement: PropTypes.string,
popperRef: PropTypes.func,
@@ -140,6 +143,10 @@ const History = observer(
this.appendToHistory();
}
+ handleClickOutside = action(event => {
+ this.collapse.hide();
+ });
+
render() {
const { alertStore } = this.props;
@@ -159,7 +166,7 @@ const History = observer(