mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
feat(ui): render per grid state count
This commit is contained in:
@@ -16,8 +16,9 @@ import { faAngleDoubleDown } from "@fortawesome/free-solid-svg-icons/faAngleDoub
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { APIGroup } from "Models/API";
|
||||
import { APIGrid } from "Models/API";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { FilteringCounterBadge } from "Components/Labels/FilteringCounterBadge";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { AlertGroup } from "./AlertGroup";
|
||||
|
||||
@@ -29,9 +30,7 @@ const Grid = observer(
|
||||
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,
|
||||
grid: APIGrid.isRequired,
|
||||
};
|
||||
|
||||
// store reference to generated masonry component so we can call it
|
||||
@@ -74,11 +73,11 @@ const Grid = observer(
|
||||
loadMoreStep = 30;
|
||||
|
||||
loadMore = action(() => {
|
||||
const { gridAlertGroups } = this.props;
|
||||
const { grid } = this.props;
|
||||
|
||||
this.groupsToRender.value = Math.min(
|
||||
this.groupsToRender.value + this.loadMoreStep,
|
||||
gridAlertGroups.length
|
||||
grid.alertGroups.length
|
||||
);
|
||||
});
|
||||
|
||||
@@ -95,13 +94,13 @@ const Grid = observer(
|
||||
);
|
||||
|
||||
componentDidUpdate() {
|
||||
const { gridAlertGroups } = this.props;
|
||||
const { grid } = this.props;
|
||||
|
||||
this.masonryRepack();
|
||||
|
||||
if (this.groupsToRender.value > gridAlertGroups.length) {
|
||||
if (this.groupsToRender.value > grid.alertGroups.length) {
|
||||
this.groupsToRender.setValue(
|
||||
Math.max(this.initial, gridAlertGroups.length)
|
||||
Math.max(this.initial, grid.alertGroups.length)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -113,28 +112,50 @@ const Grid = observer(
|
||||
silenceFormStore,
|
||||
gridSizesConfig,
|
||||
groupWidth,
|
||||
gridLabelName,
|
||||
gridLabelValue,
|
||||
gridAlertGroups,
|
||||
grid,
|
||||
} = 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>
|
||||
{alertStore.data.grids.length > 1 && (
|
||||
<h5 className="d-flex flex-row justify-content-between px-2 py-1 mx-0 mt-2 mb-0 bg-light">
|
||||
{grid.alertGroups.length > 1 && (
|
||||
<span className="flex-shrink-0 flex-grow-0 ml-0 mr-2">
|
||||
<FilteringCounterBadge
|
||||
name="@state"
|
||||
value="unprocessed"
|
||||
counter={grid.stateCount.unprocessed}
|
||||
themed={true}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
<FilteringCounterBadge
|
||||
name="@state"
|
||||
value="suppressed"
|
||||
counter={grid.stateCount.suppressed}
|
||||
themed={true}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
<FilteringCounterBadge
|
||||
name="@state"
|
||||
value="active"
|
||||
counter={grid.stateCount.active}
|
||||
themed={true}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className="flex-shrink-1 flex-grow-1 text-center"
|
||||
style={{ minWidth: "0px" }}
|
||||
>
|
||||
<FilteringLabel
|
||||
key={gridLabelValue}
|
||||
name={gridLabelName}
|
||||
value={gridLabelValue}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
{grid.labelName !== "" && grid.labelValue !== "" && (
|
||||
<FilteringLabel
|
||||
key={grid.labelValue}
|
||||
name={grid.labelName}
|
||||
value={grid.labelValue}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span
|
||||
className="flex-shrink-0 flex-grow-0 text-white cursor-pointer badge px-0 components-label ml-2 mr-0"
|
||||
@@ -158,7 +179,7 @@ const Grid = observer(
|
||||
hasMore={false}
|
||||
>
|
||||
{this.gridToggle.show
|
||||
? gridAlertGroups
|
||||
? grid.alertGroups
|
||||
.slice(0, this.groupsToRender.value)
|
||||
.map((group) => (
|
||||
<AlertGroup
|
||||
@@ -179,7 +200,7 @@ const Grid = observer(
|
||||
))
|
||||
: []}
|
||||
</MasonryInfiniteScroller>
|
||||
{gridAlertGroups.length > this.groupsToRender.value && (
|
||||
{grid.alertGroups.length > this.groupsToRender.value && (
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<span className="flex-shrink-1 flex-grow-1 text-center">
|
||||
<button
|
||||
|
||||
@@ -104,9 +104,7 @@ const AlertGrid = observer(
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={this.viewport.gridSizesConfig}
|
||||
groupWidth={this.viewport.groupWidth}
|
||||
gridLabelName={grid.labelName}
|
||||
gridLabelValue={grid.labelValue}
|
||||
gridAlertGroups={grid.alertGroups}
|
||||
grid={grid}
|
||||
/>
|
||||
))}
|
||||
</React.Fragment>
|
||||
|
||||
@@ -46,6 +46,19 @@ const ShallowAlertGrid = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const MockGrid = () => ({
|
||||
labelName: "",
|
||||
labelValue: "",
|
||||
alertGroups: alertStore.data.grids.length
|
||||
? alertStore.data.grids[0].alertGroups
|
||||
: [],
|
||||
stateCount: {
|
||||
unprocessed: 1,
|
||||
suppressed: 2,
|
||||
active: 3,
|
||||
},
|
||||
});
|
||||
|
||||
const ShallowGrid = () => {
|
||||
return shallow(
|
||||
<Grid
|
||||
@@ -54,11 +67,7 @@ const ShallowGrid = () => {
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={GridSizesConfig(1024, 420)}
|
||||
groupWidth={420}
|
||||
gridLabelName=""
|
||||
gridLabelValue=""
|
||||
gridAlertGroups={
|
||||
alertStore.data.grids.length ? alertStore.data.grids[0].alertGroups : []
|
||||
}
|
||||
grid={MockGrid()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -71,11 +80,7 @@ const MountedGrid = () => {
|
||||
settingsStore={settingsStore}
|
||||
gridSizesConfig={GridSizesConfig(1024, 420)}
|
||||
groupWidth={420}
|
||||
gridLabelName=""
|
||||
gridLabelValue=""
|
||||
gridAlertGroups={
|
||||
alertStore.data.grids.length ? alertStore.data.grids[0].alertGroups : []
|
||||
}
|
||||
grid={MockGrid()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -113,6 +118,11 @@ const MockGroupList = (count, alertPerGroup) => {
|
||||
labelName: "",
|
||||
labelValue: "",
|
||||
alertGroups: groups,
|
||||
stateCount: {
|
||||
unprocessed: 1,
|
||||
suppressed: 2,
|
||||
active: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -144,12 +154,12 @@ describe("<Grid />", () => {
|
||||
expect(tree.instance().groupsToRender.value).toBe(80);
|
||||
|
||||
MockGroupList(10, 5);
|
||||
tree.setProps({ gridAlertGroups: alertStore.data.grids[0].alertGroups });
|
||||
tree.setProps({ grid: MockGrid() });
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
expect(tree.instance().groupsToRender.value).toBe(50);
|
||||
|
||||
MockGroupList(100, 5);
|
||||
tree.setProps({ gridAlertGroups: alertStore.data.grids[0].alertGroups });
|
||||
tree.setProps({ grid: MockGrid() });
|
||||
expect(tree.find("AlertGroup")).toHaveLength(50);
|
||||
expect(tree.instance().groupsToRender.value).toBe(50);
|
||||
});
|
||||
@@ -209,11 +219,20 @@ describe("<Grid />", () => {
|
||||
|
||||
it("click on the grid toggle toggles all groups", () => {
|
||||
MockGroupList(10, 3);
|
||||
const groups = alertStore.data.grids[0].alertGroups;
|
||||
alertStore.data.grids = [
|
||||
{
|
||||
labelName: "foo",
|
||||
labelValue: "bar",
|
||||
alertGroups: groups,
|
||||
},
|
||||
{
|
||||
labelName: "foo",
|
||||
labelValue: "",
|
||||
alertGroups: [],
|
||||
},
|
||||
];
|
||||
const tree = MountedGrid();
|
||||
tree.setProps({
|
||||
gridLabelName: "foo",
|
||||
gridLabelValue: "bar",
|
||||
});
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
|
||||
tree.find("span.cursor-pointer").at(0).simulate("click");
|
||||
@@ -223,6 +242,41 @@ describe("<Grid />", () => {
|
||||
expect(tree.find("AlertGroup")).toHaveLength(10);
|
||||
});
|
||||
|
||||
it("renders filter badge for grids with a value", () => {
|
||||
MockGroupList(1, 1);
|
||||
const tree = MountedGrid();
|
||||
const grid = MockGrid();
|
||||
grid.labelName = "foo";
|
||||
grid.labelValue = "bar";
|
||||
grid.stateCount = {
|
||||
unprocessed: 0,
|
||||
suppressed: 0,
|
||||
active: 0,
|
||||
};
|
||||
alertStore.data.grids = [MockGrid(), MockGrid()];
|
||||
tree.setProps({ grid: grid });
|
||||
expect(tree.find("h5").at(0).find("FilteringLabel")).toHaveLength(1);
|
||||
expect(tree.find("h5").at(0).find("FilteringLabel").text()).toBe(
|
||||
"foo: bar"
|
||||
);
|
||||
});
|
||||
|
||||
it("doesn't render filter badge for grids with no value", () => {
|
||||
MockGroupList(1, 1);
|
||||
const tree = MountedGrid();
|
||||
const grid = MockGrid();
|
||||
grid.labelName = "foo";
|
||||
grid.labelValue = "";
|
||||
grid.stateCount = {
|
||||
unprocessed: 0,
|
||||
suppressed: 0,
|
||||
active: 0,
|
||||
};
|
||||
alertStore.data.grids = [MockGrid(), MockGrid()];
|
||||
tree.setProps({ grid: grid });
|
||||
expect(tree.find("h5").at(0).find("FilteringLabel")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("left click on a group collapse toggle only toggles clicked group", () => {
|
||||
MockGroupList(10, 3);
|
||||
const tree = MountedGrid();
|
||||
|
||||
@@ -28,17 +28,19 @@ const APIAlert = PropTypes.exact({
|
||||
receiver: PropTypes.string.isRequired,
|
||||
});
|
||||
|
||||
const APIStateCount = PropTypes.exact({
|
||||
active: PropTypes.number.isRequired,
|
||||
suppressed: PropTypes.number.isRequired,
|
||||
unprocessed: PropTypes.number.isRequired,
|
||||
});
|
||||
|
||||
const APIGroup = PropTypes.exact({
|
||||
receiver: PropTypes.string.isRequired,
|
||||
labels: PropTypes.object.isRequired,
|
||||
alerts: PropTypes.arrayOf(APIAlert),
|
||||
id: PropTypes.string.isRequired,
|
||||
alertmanagerCount: PropTypes.objectOf(PropTypes.number).isRequired,
|
||||
stateCount: PropTypes.exact({
|
||||
active: PropTypes.number.isRequired,
|
||||
suppressed: PropTypes.number.isRequired,
|
||||
unprocessed: PropTypes.number.isRequired,
|
||||
}),
|
||||
stateCount: APIStateCount.isRequired,
|
||||
shared: PropTypes.exact({
|
||||
annotations: PropTypes.arrayOf(Annotation).isRequired,
|
||||
labels: PropTypes.object.isRequired,
|
||||
@@ -79,6 +81,13 @@ const APIAlertmanagerUpstream = PropTypes.exact({
|
||||
clusterMembers: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
});
|
||||
|
||||
const APIGrid = PropTypes.exact({
|
||||
labelName: PropTypes.string.isRequired,
|
||||
labelValue: PropTypes.string.isRequired,
|
||||
alertGroups: PropTypes.arrayOf(APIGroup).isRequired,
|
||||
stateCount: APIStateCount.isRequired,
|
||||
});
|
||||
|
||||
export {
|
||||
APIAlert,
|
||||
APIGroup,
|
||||
@@ -86,4 +95,5 @@ export {
|
||||
APISilenceMatcher,
|
||||
APIAlertAlertmanagerState,
|
||||
APIAlertmanagerUpstream,
|
||||
APIGrid,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user