mirror of
https://github.com/prymitive/karma
synced 2026-05-11 03:46:48 +00:00
feat(ui): support multiple grids in the UI
This commit is contained in:
202
ui/src/Components/Grid/AlertGrid/Grid.js
Normal file
202
ui/src/Components/Grid/AlertGrid/Grid.js
Normal file
@@ -0,0 +1,202 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { observable, action } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
import debounce from "lodash/debounce";
|
||||
|
||||
import MasonryInfiniteScroller from "react-masonry-infinite";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
||||
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
||||
import { faAngleDoubleDown } from "@fortawesome/free-solid-svg-icons/faAngleDoubleDown";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { APIGroup } from "Models/API";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { AlertGroup } from "./AlertGroup";
|
||||
|
||||
const Grid = observer(
|
||||
class Grid extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired,
|
||||
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
|
||||
gridSizesConfig: PropTypes.array.isRequired,
|
||||
groupWidth: PropTypes.number.isRequired,
|
||||
gridLabelName: PropTypes.string.isRequired,
|
||||
gridLabelValue: PropTypes.string.isRequired,
|
||||
gridAlertGroups: PropTypes.arrayOf(APIGroup).isRequired,
|
||||
};
|
||||
|
||||
// store reference to generated masonry component so we can call it
|
||||
// to repack the grid after any component was re-rendered, which could
|
||||
// alter its size breaking grid layout
|
||||
masonryComponentReference = observable(
|
||||
{ ref: false },
|
||||
{},
|
||||
{ name: "Masonry reference" }
|
||||
);
|
||||
// store it for later
|
||||
storeMasonryRef = action((ref) => {
|
||||
this.masonryComponentReference.ref = ref;
|
||||
});
|
||||
// used to call forcePack() which will repack all grid elements
|
||||
// (alert groups), this needs to be called if any group size changes
|
||||
masonryRepack = debounce(
|
||||
action(() => {
|
||||
if (this.masonryComponentReference.ref) {
|
||||
this.masonryComponentReference.ref.forcePack();
|
||||
}
|
||||
}),
|
||||
10
|
||||
);
|
||||
|
||||
initial = 50;
|
||||
groupsToRender = observable(
|
||||
{
|
||||
value: this.initial,
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
},
|
||||
},
|
||||
{
|
||||
setValue: action.bound,
|
||||
},
|
||||
{ name: "Groups to render" }
|
||||
);
|
||||
// how many groups add to render count when user scrolls to the bottom
|
||||
loadMoreStep = 30;
|
||||
|
||||
loadMore = action(() => {
|
||||
const { gridAlertGroups } = this.props;
|
||||
|
||||
this.groupsToRender.value = Math.min(
|
||||
this.groupsToRender.value + this.loadMoreStep,
|
||||
gridAlertGroups.length
|
||||
);
|
||||
});
|
||||
|
||||
gridToggle = observable(
|
||||
{
|
||||
show: true,
|
||||
toggle() {
|
||||
this.show = !this.show;
|
||||
},
|
||||
},
|
||||
{
|
||||
toggle: action.bound,
|
||||
}
|
||||
);
|
||||
|
||||
componentDidUpdate() {
|
||||
const { gridAlertGroups } = this.props;
|
||||
|
||||
this.masonryRepack();
|
||||
|
||||
if (this.groupsToRender.value > gridAlertGroups.length) {
|
||||
this.groupsToRender.setValue(
|
||||
Math.max(this.initial, gridAlertGroups.length)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
alertStore,
|
||||
settingsStore,
|
||||
silenceFormStore,
|
||||
gridSizesConfig,
|
||||
groupWidth,
|
||||
gridLabelName,
|
||||
gridLabelValue,
|
||||
gridAlertGroups,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{gridLabelName !== "" && gridLabelValue !== "" && (
|
||||
<h5 className="d-flex flex-row justify-content-between px-2 mx-0 mt-2 mb-0 bg-secondary">
|
||||
<span className="flex-shrink-0 flex-grow-0 text-white badge px-0 components-label ml-0 mr-2">
|
||||
{gridAlertGroups.length}
|
||||
</span>
|
||||
<span
|
||||
className="flex-shrink-1 flex-grow-1 text-center"
|
||||
style={{ minWidth: "0px" }}
|
||||
>
|
||||
<FilteringLabel
|
||||
key={gridLabelValue}
|
||||
name={gridLabelName}
|
||||
value={gridLabelValue}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="flex-shrink-0 flex-grow-0 text-white cursor-pointer badge px-0 components-label ml-2 mr-0"
|
||||
onClick={this.gridToggle.toggle}
|
||||
>
|
||||
<TooltipWrapper title="Click to toggle this grid details">
|
||||
<FontAwesomeIcon
|
||||
icon={this.gridToggle.show ? faChevronDown : faChevronUp}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
</h5>
|
||||
)}
|
||||
<MasonryInfiniteScroller
|
||||
key={settingsStore.gridConfig.config.groupWidth}
|
||||
ref={this.storeMasonryRef}
|
||||
position={false}
|
||||
pack={true}
|
||||
sizes={gridSizesConfig}
|
||||
loadMore={this.loadMore}
|
||||
hasMore={false}
|
||||
>
|
||||
{this.gridToggle.show
|
||||
? gridAlertGroups
|
||||
.slice(0, this.groupsToRender.value)
|
||||
.map((group) => (
|
||||
<AlertGroup
|
||||
key={group.id}
|
||||
group={group}
|
||||
showAlertmanagers={
|
||||
Object.keys(alertStore.data.upstreams.clusters).length >
|
||||
1
|
||||
}
|
||||
afterUpdate={this.masonryRepack}
|
||||
alertStore={alertStore}
|
||||
settingsStore={settingsStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
style={{
|
||||
width: groupWidth,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
: []}
|
||||
</MasonryInfiniteScroller>
|
||||
{gridAlertGroups.length > this.groupsToRender.value && (
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<span className="flex-shrink-1 flex-grow-1 text-center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary mb-3"
|
||||
onClick={this.loadMore}
|
||||
>
|
||||
<FontAwesomeIcon className="mr-2" icon={faAngleDoubleDown} />
|
||||
Load more
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { Grid };
|
||||
@@ -10,15 +10,10 @@ import debounce from "lodash/debounce";
|
||||
|
||||
import ReactResizeDetector from "react-resize-detector";
|
||||
|
||||
import MasonryInfiniteScroller from "react-masonry-infinite";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCircleNotch } from "@fortawesome/free-solid-svg-icons/faCircleNotch";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { AlertGroup } from "./AlertGroup";
|
||||
import { Grid } from "./Grid";
|
||||
import { GridSizesConfig, GetGridElementWidth } from "./GridSize";
|
||||
|
||||
const AlertGrid = observer(
|
||||
@@ -69,54 +64,6 @@ const AlertGrid = observer(
|
||||
this.viewport.updateWidths(document.body.clientWidth, window.innerWidth);
|
||||
}, 100);
|
||||
|
||||
// store reference to generated masonry component so we can call it
|
||||
// to repack the grid after any component was re-rendered, which could
|
||||
// alter its size breaking grid layout
|
||||
masonryComponentReference = observable(
|
||||
{ ref: false },
|
||||
{},
|
||||
{ name: "Masonry reference" }
|
||||
);
|
||||
// store it for later
|
||||
storeMasonryRef = action((ref) => {
|
||||
this.masonryComponentReference.ref = ref;
|
||||
});
|
||||
// used to call forcePack() which will repack all grid elements
|
||||
// (alert groups), this needs to be called if any group size changes
|
||||
masonryRepack = debounce(
|
||||
action(() => {
|
||||
if (this.masonryComponentReference.ref) {
|
||||
this.masonryComponentReference.ref.forcePack();
|
||||
}
|
||||
}),
|
||||
10
|
||||
);
|
||||
|
||||
initial = 50;
|
||||
groupsToRender = observable(
|
||||
{
|
||||
value: this.initial,
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
},
|
||||
},
|
||||
{
|
||||
setValue: action.bound,
|
||||
},
|
||||
{ name: "Groups to render" }
|
||||
);
|
||||
// how many groups add to render count when user scrolls to the bottom
|
||||
loadMoreStep = 30;
|
||||
|
||||
loadMore = action(() => {
|
||||
const { alertStore } = this.props;
|
||||
|
||||
this.groupsToRender.value = Math.min(
|
||||
this.groupsToRender.value + this.loadMoreStep,
|
||||
alertStore.data.groups.length
|
||||
);
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
// We have font-display:swap set for font assets, this means that on initial
|
||||
// render a fallback font might be used and later swapped for the final one
|
||||
@@ -135,16 +82,6 @@ const AlertGrid = observer(
|
||||
window.addEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { alertStore } = this.props;
|
||||
|
||||
if (this.groupsToRender.value > alertStore.data.groups.length) {
|
||||
this.groupsToRender.setValue(
|
||||
Math.max(this.initial, alertStore.data.groups.length)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
@@ -159,40 +96,19 @@ const AlertGrid = observer(
|
||||
handleHeight
|
||||
onResize={debounce(this.handleResize, 100)}
|
||||
/>
|
||||
<MasonryInfiniteScroller
|
||||
key={settingsStore.gridConfig.config.groupWidth}
|
||||
ref={this.storeMasonryRef}
|
||||
position={false}
|
||||
pack={true}
|
||||
sizes={this.viewport.gridSizesConfig}
|
||||
loadMore={this.loadMore}
|
||||
hasMore={this.groupsToRender.value < alertStore.data.groups.length}
|
||||
threshold={50}
|
||||
loader={
|
||||
<div key="loader" className="text-center text-muted py-3">
|
||||
<FontAwesomeIcon icon={faCircleNotch} size="lg" spin />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{alertStore.data.groups
|
||||
.slice(0, this.groupsToRender.value)
|
||||
.map((group) => (
|
||||
<AlertGroup
|
||||
key={group.id}
|
||||
group={group}
|
||||
showAlertmanagers={
|
||||
Object.keys(alertStore.data.upstreams.clusters).length > 1
|
||||
}
|
||||
afterUpdate={this.masonryRepack}
|
||||
alertStore={alertStore}
|
||||
settingsStore={settingsStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
style={{
|
||||
width: this.viewport.groupWidth,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</MasonryInfiniteScroller>
|
||||
{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}
|
||||
gridLabelName={grid.labelName}
|
||||
gridLabelValue={grid.labelValue}
|
||||
gridAlertGroups={grid.alertGroups}
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ import { mockMatchMedia } from "__mocks__/matchMedia";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { GetGridElementWidth } from "./GridSize";
|
||||
import { GetGridElementWidth, GridSizesConfig } from "./GridSize";
|
||||
import { Grid } from "./Grid";
|
||||
import { AlertGrid } from ".";
|
||||
|
||||
let alertStore;
|
||||
@@ -45,12 +46,36 @@ const ShallowAlertGrid = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const MountedAlertGroup = () => {
|
||||
return mount(
|
||||
<AlertGrid
|
||||
const ShallowGrid = () => {
|
||||
return shallow(
|
||||
<Grid
|
||||
alertStore={alertStore}
|
||||
settingsStore={settingsStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={GridSizesConfig(1024, 420)}
|
||||
groupWidth={420}
|
||||
gridLabelName=""
|
||||
gridLabelValue=""
|
||||
gridAlertGroups={
|
||||
alertStore.data.grids.length ? alertStore.data.grids[0].alertGroups : []
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const MountedGrid = () => {
|
||||
return mount(
|
||||
<Grid
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={GridSizesConfig(1024, 420)}
|
||||
groupWidth={420}
|
||||
gridLabelName=""
|
||||
gridLabelValue=""
|
||||
gridAlertGroups={
|
||||
alertStore.data.grids.length ? alertStore.data.grids[0].alertGroups : []
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -83,58 +108,54 @@ const MockGroupList = (count, alertPerGroup) => {
|
||||
instances: [{ name: "am", uri: "http://am", error: "" }],
|
||||
clusters: { am: ["am"] },
|
||||
};
|
||||
alertStore.data.groups = groups;
|
||||
alertStore.data.grids = [
|
||||
{
|
||||
labelName: "",
|
||||
labelValue: "",
|
||||
alertGroups: groups,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const VerifyColumnCount = (innerWidth, outerWidth, columns) => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
tree.instance().viewport.updateWidths(innerWidth, outerWidth);
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(
|
||||
Math.floor(innerWidth / columns)
|
||||
);
|
||||
};
|
||||
|
||||
describe("<AlertGrid />", () => {
|
||||
describe("<Grid />", () => {
|
||||
it("renders only first 50 alert groups", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const alertGroups = tree.find("AlertGroup");
|
||||
expect(alertGroups).toHaveLength(50);
|
||||
});
|
||||
|
||||
it("appends 30 groups after loadMore() call", () => {
|
||||
it("appends 30 groups after clicking 'Load More' button", () => {
|
||||
MockGroupList(100, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
// call it directly, it should happen on scroll to the bottom of the page
|
||||
tree.instance().loadMore();
|
||||
const tree = ShallowGrid();
|
||||
tree.find("button").simulate("click");
|
||||
const alertGroups = tree.find("AlertGroup");
|
||||
expect(alertGroups).toHaveLength(80);
|
||||
});
|
||||
|
||||
it("resets groupsToRender.value back to 50 if current value is > alertStore.data.groups.length", () => {
|
||||
it("resets groupsToRender.value back to 50 if current value is more than group alerts", () => {
|
||||
MockGroupList(100, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
expect(tree.find("AlertGroup")).toHaveLength(50);
|
||||
expect(tree.instance().groupsToRender.value).toBe(50);
|
||||
|
||||
tree.instance().loadMore();
|
||||
tree.find("button").simulate("click");
|
||||
expect(tree.find("AlertGroup")).toHaveLength(80);
|
||||
expect(tree.instance().groupsToRender.value).toBe(80);
|
||||
|
||||
MockGroupList(10, 5);
|
||||
tree.instance().componentDidUpdate();
|
||||
tree.setProps({ gridAlertGroups: alertStore.data.grids[0].alertGroups });
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
expect(tree.instance().groupsToRender.value).toBe(50);
|
||||
|
||||
MockGroupList(100, 5);
|
||||
tree.instance().componentDidUpdate();
|
||||
tree.setProps({ gridAlertGroups: alertStore.data.grids[0].alertGroups });
|
||||
expect(tree.find("AlertGroup")).toHaveLength(50);
|
||||
expect(tree.instance().groupsToRender.value).toBe(50);
|
||||
});
|
||||
|
||||
it("calling masonryRepack() calls forcePack() on Masonry instance`", () => {
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const instance = tree.instance();
|
||||
// it's a shallow render so we don't really have masonry mounted, fake it
|
||||
instance.masonryComponentReference.ref = {
|
||||
@@ -145,28 +166,28 @@ describe("<AlertGrid />", () => {
|
||||
});
|
||||
|
||||
it("masonryRepack() doesn't crash when masonryComponentReference.ref=false`", () => {
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const instance = tree.instance();
|
||||
instance.masonryComponentReference.ref = false;
|
||||
instance.masonryRepack();
|
||||
});
|
||||
|
||||
it("masonryRepack() doesn't crash when masonryComponentReference.ref=null`", () => {
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const instance = tree.instance();
|
||||
instance.masonryComponentReference.ref = null;
|
||||
instance.masonryRepack();
|
||||
});
|
||||
|
||||
it("masonryRepack() doesn't crash when masonryComponentReference.ref=undefined`", () => {
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const instance = tree.instance();
|
||||
instance.masonryComponentReference.ref = undefined;
|
||||
instance.masonryRepack();
|
||||
});
|
||||
|
||||
it("calling storeMasonryRef() saves the ref in local store", () => {
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const instance = tree.instance();
|
||||
instance.storeMasonryRef("foo");
|
||||
expect(instance.masonryComponentReference.ref).toEqual("foo");
|
||||
@@ -177,7 +198,7 @@ describe("<AlertGrid />", () => {
|
||||
settingsStore.gridConfig.options.disabled.value;
|
||||
settingsStore.gridConfig.config.reverseSort = false;
|
||||
MockGroupList(3, 1);
|
||||
const tree = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
const alertGroups = tree.find("AlertGroup");
|
||||
expect(alertGroups.map((g) => g.props().group.id)).toEqual([
|
||||
"id1",
|
||||
@@ -186,6 +207,85 @@ describe("<AlertGrid />", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("click on the grid toggle toggles all groups", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedGrid();
|
||||
tree.setProps({
|
||||
gridLabelName: "foo",
|
||||
gridLabelValue: "bar",
|
||||
});
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
|
||||
tree.find("span.cursor-pointer").at(0).simulate("click");
|
||||
expect(tree.find("AlertGroup")).toHaveLength(0);
|
||||
|
||||
tree.find("span.cursor-pointer").at(0).simulate("click");
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
});
|
||||
|
||||
it("left click on a group collapse toggle only toggles clicked group", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedGrid();
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(3);
|
||||
}
|
||||
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(2)
|
||||
.find("GroupHeader")
|
||||
.find("span.cursor-pointer")
|
||||
.at(1)
|
||||
.simulate("click");
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(
|
||||
i === 2 ? 0 : 3
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("left click + alt on a group collapse toggle toggles all groups", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedGrid();
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(3);
|
||||
}
|
||||
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(2)
|
||||
.find("GroupHeader")
|
||||
.find("span.cursor-pointer")
|
||||
.at(1)
|
||||
.simulate("click", { altKey: true });
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("<AlertGrid />", () => {
|
||||
const VerifyColumnCount = (innerWidth, outerWidth, columns) => {
|
||||
MockGroupList(60, 5);
|
||||
|
||||
const wrapper = ShallowAlertGrid();
|
||||
wrapper.instance().viewport.updateWidths(innerWidth, outerWidth);
|
||||
|
||||
const tree = ShallowGrid();
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(
|
||||
Math.floor(innerWidth / columns)
|
||||
);
|
||||
};
|
||||
|
||||
it("doesn't throw errors after FontFaceObserver timeout", () => {
|
||||
MockGroupList(60, 5);
|
||||
ShallowAlertGrid();
|
||||
@@ -261,13 +361,24 @@ describe("<AlertGrid />", () => {
|
||||
|
||||
it("viewport resize also resizes alert groups", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
|
||||
const wrapper = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
|
||||
// set initial width
|
||||
tree.instance().viewport.updateWidths(1980, 1980);
|
||||
wrapper.instance().viewport.updateWidths(1980, 1980);
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(1980 / 4);
|
||||
|
||||
// then resize and verify if column count was changed
|
||||
tree.instance().viewport.updateWidths(1000, 1000);
|
||||
wrapper.instance().viewport.updateWidths(1000, 1000);
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(1000 / 2);
|
||||
});
|
||||
|
||||
@@ -275,13 +386,23 @@ describe("<AlertGrid />", () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
const wrapper = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
|
||||
// set initial width
|
||||
tree.instance().viewport.updateWidths(1600, 1600);
|
||||
wrapper.instance().viewport.updateWidths(1600, 1600);
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(400);
|
||||
|
||||
// then resize and verify if column count was changed
|
||||
tree.instance().viewport.updateWidths(1584, 1600);
|
||||
wrapper.instance().viewport.updateWidths(1584, 1600);
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
expect(tree.find("AlertGroup").at(0).props().style.width).toBe(396);
|
||||
});
|
||||
|
||||
@@ -297,14 +418,20 @@ describe("<AlertGrid />", () => {
|
||||
|
||||
it("viewport resize doesn't allow loops", () => {
|
||||
settingsStore.gridConfig.config.groupWidth = 400;
|
||||
const tree = ShallowAlertGrid();
|
||||
|
||||
MockGroupList(60, 5);
|
||||
const wrapper = ShallowAlertGrid();
|
||||
const tree = ShallowGrid();
|
||||
|
||||
let results = [];
|
||||
for (var index = 0; index < 14; index++) {
|
||||
MockGroupList(60, 5);
|
||||
tree
|
||||
wrapper
|
||||
.instance()
|
||||
.viewport.updateWidths(index % 2 === 0 ? 1600 : 1584, 1600);
|
||||
tree.setProps({
|
||||
gridSizesConfig: wrapper.instance().viewport.gridSizesConfig,
|
||||
groupWidth: wrapper.instance().viewport.groupWidth,
|
||||
});
|
||||
results.push(tree.find("AlertGroup").at(0).props().style.width);
|
||||
}
|
||||
|
||||
@@ -326,50 +453,6 @@ describe("<AlertGrid />", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("left click on a group collapse toggle only toggles clicked group", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedAlertGroup();
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(3);
|
||||
}
|
||||
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(2)
|
||||
.find("GroupHeader")
|
||||
.find("span.cursor-pointer")
|
||||
.at(1)
|
||||
.simulate("click");
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(
|
||||
i === 2 ? 0 : 3
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("left click + alt on a group collapse toggle toggles all groups", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedAlertGroup();
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(3);
|
||||
}
|
||||
|
||||
tree
|
||||
.find("AlertGroup")
|
||||
.at(2)
|
||||
.find("GroupHeader")
|
||||
.find("span.cursor-pointer")
|
||||
.at(1)
|
||||
.simulate("click", { altKey: true });
|
||||
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
expect(tree.find("AlertGroup").at(i).find("Alert")).toHaveLength(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("doesn't crash on unmount", () => {
|
||||
MockGroupList(60, 5);
|
||||
const tree = ShallowAlertGrid();
|
||||
|
||||
@@ -243,7 +243,13 @@ const MockGrid = (alertStore) => {
|
||||
],
|
||||
clusters: { am: ["am1", "am2"], failed: ["failed"] },
|
||||
};
|
||||
alertStore.data.groups = groups;
|
||||
alertStore.data.grids = [
|
||||
{
|
||||
labelName: "",
|
||||
labelValue: "",
|
||||
alertGroups: groups,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export { MockGrid };
|
||||
|
||||
Reference in New Issue
Block a user