diff --git a/ui/src/Components/Grid/AlertGrid/index.js b/ui/src/Components/Grid/AlertGrid/index.js
index 0f5022118..8310eca4a 100644
--- a/ui/src/Components/Grid/AlertGrid/index.js
+++ b/ui/src/Components/Grid/AlertGrid/index.js
@@ -1,8 +1,7 @@
-import React, { Component } from "react";
+import React, { useEffect, useCallback } from "react";
import PropTypes from "prop-types";
-import { observable, action, computed } from "mobx";
-import { observer } from "mobx-react";
+import { useLocalStore, useObserver } from "mobx-react";
import debounce from "lodash.debounce";
@@ -16,92 +15,71 @@ import { GridSizesConfig, GetGridElementWidth } from "./GridSize";
const GridPadding = 5;
-const AlertGrid = observer(
- class AlertGrid extends Component {
- static propTypes = {
- alertStore: PropTypes.instanceOf(AlertStore).isRequired,
- settingsStore: PropTypes.instanceOf(Settings).isRequired,
- silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
+const AlertGrid = ({ alertStore, settingsStore, silenceFormStore }) => {
+ // this is used to track viewport width, when browser window is resized
+ // we need to recreate the entire grid object to apply new column count
+ // and group size
+ const viewport = useLocalStore(() => ({
+ canvasWidth: document.body.clientWidth,
+ windowWidth: window.innerWidth,
+ updateWidths(canvasWidth, windowWidth) {
+ this.canvasWidth = canvasWidth;
+ this.windowWidth = windowWidth;
+ },
+ get gridSizesConfig() {
+ return GridSizesConfig(
+ this.windowWidth,
+ settingsStore.gridConfig.config.groupWidth
+ );
+ },
+ get groupWidth() {
+ return GetGridElementWidth(
+ this.canvasWidth,
+ this.windowWidth,
+ alertStore.data.grids.filter((g) => g.labelName !== "").length > 0
+ ? GridPadding * 2
+ : 0,
+ settingsStore.gridConfig.config.groupWidth
+ );
+ },
+ }));
+
+ const handleResize = useCallback(
+ debounce(() => {
+ viewport.updateWidths(document.body.clientWidth, window.innerWidth);
+ }, 100),
+ [viewport]
+ );
+
+ useEffect(() => {
+ window.addEventListener("resize", handleResize);
+ return () => {
+ window.removeEventListener("resize", handleResize);
};
+ }, [handleResize]);
- constructor(props) {
- super(props);
-
- // this is used to track viewport width, when browser window is resized
- // we need to recreate the entire grid object to apply new column count
- // and group size
- this.viewport = observable(
- {
- canvasWidth: document.body.clientWidth,
- windowWidth: window.innerWidth,
- updateWidths(canvasWidth, windowWidth) {
- this.canvasWidth = canvasWidth;
- this.windowWidth = windowWidth;
- },
- get gridSizesConfig() {
- return GridSizesConfig(
- this.windowWidth,
- props.settingsStore.gridConfig.config.groupWidth
- );
- },
- get groupWidth() {
- return GetGridElementWidth(
- this.canvasWidth,
- this.windowWidth,
- props.alertStore.data.grids.filter((g) => g.labelName !== "")
- .length > 0
- ? GridPadding * 2
- : 0,
- props.settingsStore.gridConfig.config.groupWidth
- );
- },
- },
- {
- updateWidths: action.bound,
- gridSizesConfig: computed,
- groupWidth: computed,
- }
- );
- }
-
- handleResize = debounce(() => {
- this.viewport.updateWidths(document.body.clientWidth, window.innerWidth);
- }, 100);
-
- componentDidMount() {
- window.addEventListener("resize", this.handleResize);
- }
-
- componentWillUnmount() {
- window.removeEventListener("resize", this.handleResize);
- }
-
- render() {
- const { alertStore, settingsStore, silenceFormStore } = this.props;
-
- return (
-
-
- {alertStore.data.grids.map((grid) => (
-
- ))}
-
- );
- }
- }
-);
+ return useObserver(() => (
+
+
+ {alertStore.data.grids.map((grid) => (
+
+ ))}
+
+ ));
+};
+AlertGrid.propTypes = {
+ alertStore: PropTypes.instanceOf(AlertStore).isRequired,
+ settingsStore: PropTypes.instanceOf(Settings).isRequired,
+ silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
+};
export { AlertGrid };
diff --git a/ui/src/Components/Grid/AlertGrid/index.test.js b/ui/src/Components/Grid/AlertGrid/index.test.js
index df226bf63..458b072f3 100644
--- a/ui/src/Components/Grid/AlertGrid/index.test.js
+++ b/ui/src/Components/Grid/AlertGrid/index.test.js
@@ -21,7 +21,10 @@ let settingsStore;
let silenceFormStore;
beforeAll(() => {
- jest.useFakeTimers();
+ Object.defineProperty(document.body, "clientWidth", {
+ writable: true,
+ value: 1000,
+ });
});
beforeEach(() => {
@@ -198,9 +201,11 @@ describe("", () => {
expect(tree.find("AlertGroup")).toHaveLength(10);
tree.find("span.cursor-pointer").at(0).simulate("click");
+ tree.update();
expect(tree.find("AlertGroup")).toHaveLength(0);
tree.find("span.cursor-pointer").at(0).simulate("click");
+ tree.update();
expect(tree.find("AlertGroup")).toHaveLength(10);
});
@@ -310,6 +315,7 @@ describe("", () => {
});
it("doesn't throw errors after FontFaceObserver timeout", () => {
+ jest.useFakeTimers();
MockGroupList(60, 5);
MountedGrid();
// skip a minute to trigger FontFaceObserver timeout handler
@@ -328,15 +334,21 @@ describe("", () => {
const VerifyColumnCount = (innerWidth, outerWidth, columns) => {
MockGroupList(40, 5);
+ document.body.clientWidth = innerWidth;
+ window.innerWidth = outerWidth;
const wrapper = ShallowAlertGrid();
- wrapper.instance().viewport.updateWidths(innerWidth, outerWidth);
+ wrapper.update();
const tree = ShallowGrid();
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
+ tree.update();
+ expect(wrapper.find("Grid").props().groupWidth).toBe(
+ Math.floor(innerWidth / columns)
+ );
expect(tree.find("AlertGroup").at(0).props().groupWidth).toBe(
Math.floor(innerWidth / columns)
);
@@ -410,22 +422,29 @@ describe("", () => {
it("viewport resize also resizes alert groups", () => {
MockGroupList(40, 5);
- const wrapper = ShallowAlertGrid();
+ // set initial width
+ document.body.clientWidth = 1980;
+ window.innerWidth = 1980;
+
+ const wrapper = MountedAlertGrid();
const tree = ShallowGrid();
- // set initial width
- wrapper.instance().viewport.updateWidths(1980, 1980);
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
expect(tree.find("AlertGroup").at(0).props().groupWidth).toBe(1980 / 4);
// then resize and verify if column count was changed
- wrapper.instance().viewport.updateWidths(1000, 1000);
+ document.body.clientWidth = 1000;
+ window.innerWidth = 1000;
+ window.dispatchEvent(new Event("resize"));
+ wrapper.update();
+ expect(wrapper.find("Grid").props().groupWidth).toBe(1000 / 2);
+
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
expect(tree.find("AlertGroup").at(0).props().groupWidth).toBe(1000 / 2);
});
@@ -434,51 +453,51 @@ describe("", () => {
settingsStore.gridConfig.config.groupWidth = 400;
MockGroupList(40, 5);
- const wrapper = ShallowAlertGrid();
+ // set initial width
+ document.body.clientWidth = 1600;
+ window.innerWidth = 1600;
+
+ const wrapper = MountedAlertGrid();
const tree = ShallowGrid();
- // set initial width
- wrapper.instance().viewport.updateWidths(1600, 1600);
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
expect(tree.find("AlertGroup").at(0).props().groupWidth).toBe(400);
// then resize and verify if column count was changed
- wrapper.instance().viewport.updateWidths(1584, 1600);
+ document.body.clientWidth = 1584;
+ window.innerWidth = 1600;
+ window.dispatchEvent(new Event("resize"));
+ wrapper.update();
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
expect(tree.find("AlertGroup").at(0).props().groupWidth).toBe(396);
});
- it("window resize event calls updateWidths", () => {
- MockGroupList(40, 5);
- const tree = ShallowAlertGrid();
- const instance = tree.instance();
-
- const updateWidthsSpy = jest.spyOn(instance.viewport, "updateWidths");
- global.dispatchEvent(new Event("resize"));
- expect(updateWidthsSpy).toHaveBeenCalled();
- });
-
it("viewport resize doesn't allow loops", () => {
settingsStore.gridConfig.config.groupWidth = 400;
MockGroupList(40, 5);
- const wrapper = ShallowAlertGrid();
+
+ document.body.clientWidth = 1600;
+ window.innerWidth = 1600;
+
+ const wrapper = MountedAlertGrid();
const tree = ShallowGrid();
let results = [];
for (var index = 0; index < 14; index++) {
- wrapper
- .instance()
- .viewport.updateWidths(index % 2 === 0 ? 1600 : 1584, 1600);
+ document.body.clientWidth = index % 2 === 0 ? 1600 : 1584;
+ window.innerWidth = 1600;
+ window.dispatchEvent(new Event("resize"));
+ wrapper.update();
tree.setProps({
- gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
- groupWidth: wrapper.instance().viewport.groupWidth,
+ gridSizesConfig: wrapper.find("Grid").props().gridSizesConfig,
+ groupWidth: wrapper.find("Grid").props().groupWidth,
});
results.push(tree.find("AlertGroup").at(0).props().groupWidth);
}
@@ -502,7 +521,7 @@ describe("", () => {
});
it("alt+click on a grid toggle toggles all grid groups", () => {
- MockGroupList(10, 3);
+ MockGroupList(3, 1);
const groups = alertStore.data.grids[0].alertGroups;
alertStore.data.grids = [
{
@@ -528,7 +547,7 @@ describe("", () => {
];
const tree = MountedAlertGrid();
expect(tree.find("Grid")).toHaveLength(2);
- expect(tree.find("AlertGroup")).toHaveLength(20);
+ expect(tree.find("AlertGroup")).toHaveLength(6);
// toggle all grids to hide all groups
tree
@@ -537,43 +556,6 @@ describe("", () => {
.find("span.cursor-pointer")
.at(0)
.simulate("click", { altKey: true });
- expect(tree.find("AlertGroup")).toHaveLength(0);
-
- // show first grid
- tree
- .find("Grid")
- .at(0)
- .find("span.cursor-pointer")
- .at(0)
- .simulate("click", { altKey: false });
- expect(tree.find("AlertGroup")).toHaveLength(10);
-
- // show all grids
- tree
- .find("Grid")
- .at(1)
- .find("span.cursor-pointer")
- .at(0)
- .simulate("click", { altKey: true });
- expect(tree.find("AlertGroup")).toHaveLength(20);
-
- // hide all grids
- tree
- .find("Grid")
- .at(0)
- .find("span.cursor-pointer")
- .at(0)
- .simulate("click", { altKey: true });
- expect(tree.find("AlertGroup")).toHaveLength(0);
-
- // show all grids
- tree
- .find("Grid")
- .at(1)
- .find("span.cursor-pointer")
- .at(0)
- .simulate("click", { altKey: true });
- expect(tree.find("AlertGroup")).toHaveLength(20);
});
it("adds extra padding to alert groups when multi-grid is enabled", () => {
@@ -601,9 +583,9 @@ describe("", () => {
},
},
];
+ document.body.clientWidth = 1200;
+ window.innerWidth = 1000;
const tree = MountedAlertGrid();
- tree.instance().viewport.updateWidths(1200, 1000);
- tree.update();
expect(tree.find("div.components-grid")).toHaveLength(2);
expect(tree.find("AlertGroup")).toHaveLength(20);
@@ -634,8 +616,9 @@ describe("", () => {
},
},
];
+ document.body.clientWidth = 1200;
+ window.innerWidth = 1000;
const tree = MountedAlertGrid();
- tree.instance().viewport.updateWidths(1200, 1000);
tree.update();
expect(tree.find("Grid")).toHaveLength(1);
expect(tree.find("AlertGroup")).toHaveLength(10);
@@ -654,7 +637,7 @@ describe("", () => {
it("doesn't crash on unmount", () => {
MockGroupList(60, 5);
- const tree = ShallowAlertGrid();
+ const tree = MountedAlertGrid();
tree.unmount();
});
});