mirror of
https://github.com/prymitive/karma
synced 2026-05-09 03:36:44 +00:00
fix(ui): rewrite AlertGrid with hooks
This commit is contained in:
committed by
Łukasz Mierzwa
parent
edbc39b488
commit
8265a54058
@@ -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 (
|
||||
<React.Fragment>
|
||||
<ReactResizeDetector
|
||||
handleWidth
|
||||
handleHeight
|
||||
onResize={debounce(this.handleResize, 100)}
|
||||
/>
|
||||
{alertStore.data.grids.map((grid) => (
|
||||
<Grid
|
||||
key={`${grid.labelName}/${grid.labelValue}`}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={this.viewport.gridSizesConfig}
|
||||
groupWidth={this.viewport.groupWidth}
|
||||
grid={grid}
|
||||
outerPadding={grid.labelName !== "" ? GridPadding : 0}
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
return useObserver(() => (
|
||||
<React.Fragment>
|
||||
<ReactResizeDetector handleWidth handleHeight onResize={handleResize} />
|
||||
{alertStore.data.grids.map((grid) => (
|
||||
<Grid
|
||||
key={`${grid.labelName}/${grid.labelValue}`}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={viewport.gridSizesConfig}
|
||||
groupWidth={viewport.groupWidth}
|
||||
grid={grid}
|
||||
outerPadding={grid.labelName !== "" ? GridPadding : 0}
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
));
|
||||
};
|
||||
AlertGrid.propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired,
|
||||
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
|
||||
};
|
||||
|
||||
export { AlertGrid };
|
||||
|
||||
@@ -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("<Grid />", () => {
|
||||
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("<Grid />", () => {
|
||||
});
|
||||
|
||||
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("<AlertGrid />", () => {
|
||||
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("<AlertGrid />", () => {
|
||||
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("<AlertGrid />", () => {
|
||||
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("<AlertGrid />", () => {
|
||||
});
|
||||
|
||||
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("<AlertGrid />", () => {
|
||||
];
|
||||
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("<AlertGrid />", () => {
|
||||
.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("<AlertGrid />", () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
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("<AlertGrid />", () => {
|
||||
},
|
||||
},
|
||||
];
|
||||
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("<AlertGrid />", () => {
|
||||
|
||||
it("doesn't crash on unmount", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = MountedAlertGrid();
|
||||
tree.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user