diff --git a/ui/package-lock.json b/ui/package-lock.json
index fa8ecd6d8..eed86c407 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -12452,6 +12452,14 @@
"prop-types": "^15.6.2"
}
},
+ "react-lazily-render": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/react-lazily-render/-/react-lazily-render-1.2.0.tgz",
+ "integrity": "sha512-7G3w4m187V1VXs2LmF5e++ZPj3BqZ0lSsD63Tnz1L+MqsPCW55qqsqf1cM/uTHAR8gRK0tARosx0o9mJUyBeAg==",
+ "requires": {
+ "scrollparent": "^2.0.1"
+ }
+ },
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
@@ -13471,6 +13479,11 @@
"ajv-keywords": "^3.1.0"
}
},
+ "scrollparent": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz",
+ "integrity": "sha1-cV1bnMV3YPsivczDvvtb/gaxoxc="
+ },
"scss-tokenizer": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
diff --git a/ui/package.json b/ui/package.json
index 5ff8c80bb..5c031f15c 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -38,6 +38,7 @@
"react-input-range": "1.3.0",
"react-js-pagination": "3.0.2",
"react-json-pretty": "2.1.0",
+ "react-lazily-render": "1.2.0",
"react-linkify": "0.2.2",
"react-masonry-infinite": "1.2.2",
"react-moment": "0.9.2",
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/__snapshots__/index.test.js.snap b/ui/src/Components/Grid/AlertGrid/AlertGroup/__snapshots__/index.test.js.snap
new file mode 100644
index 000000000..f116851e6
--- /dev/null
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/__snapshots__/index.test.js.snap
@@ -0,0 +1,149 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` lazy rendering matches snapshot when invisible 1`] = `
+"
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"
+`;
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
index 3e0cc34a1..333792e8b 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js
@@ -6,6 +6,8 @@ import { observable, action, toJS } from "mobx";
import hash from "object-hash";
+import LazilyRender from "react-lazily-render";
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus";
@@ -50,6 +52,87 @@ const AllAlertsAreUsingSameAlertmanagers = alerts => {
);
};
+const AlertGroupContent = observer(
+ ({
+ alertStore,
+ silenceFormStore,
+ group,
+ showAlertmanagers,
+ afterUpdate,
+ renderConfig,
+ showLoadButtons,
+ loadLess,
+ loadMore
+ }) => (
+
+
+ {group.alerts.slice(0, renderConfig.alertsToRender).map(alert => (
+
+ ))}
+ {showLoadButtons ? (
+ -
+
+
+ {Math.min(renderConfig.alertsToRender, group.alerts.length)}
+ {" of "}
+ {group.alerts.length}
+
+
+
+ ) : null}
+
+
+ )
+);
+
+const FakeLabel = ({ width, color }) => (
+
+ {" "}
+
+);
+
+const AlertGroupPlaceholder = () => (
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+);
+
const AlertGroup = observer(
class AlertGroup extends Component {
static propTypes = {
@@ -224,56 +307,43 @@ const AlertGroup = observer(
setIsMenuOpen={this.renderConfig.setIsMenuOpen}
/>
{this.collapse.value ? null : (
-
-
- {group.alerts
- .slice(0, this.renderConfig.alertsToRender)
- .map(alert => (
-
- ))}
- {group.alerts.length > this.defaultRenderCount ? (
- -
-
-
- {Math.min(
- this.renderConfig.alertsToRender,
- group.alerts.length
- )}
- {" of "}
- {group.alerts.length}
-
-
-
- ) : null}
-
-
+ this.defaultRenderCount
+ }
+ loadLess={this.loadLess}
+ loadMore={this.loadMore}
+ />
+ }
+ placeholder={}
+ />
)}
{this.collapse.value === false && group.alerts.length > 1 ? (
-
+ }
+ placeholder={null}
/>
) : null}
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js
index c79616719..1f092d8c2 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js
@@ -6,6 +6,8 @@ import { mount } from "enzyme";
import moment from "moment";
+import toDiffableHtml from "diffable-html";
+
import { MockAlert, MockAlertGroup } from "__mocks__/Alerts.js";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
@@ -30,6 +32,12 @@ const MockGroup = groupName => {
let originalInnerWidth;
+const MockedLazyRender = jest.fn(({ content }) => {
+ return content;
+});
+
+jest.mock("react-lazily-render", () => props => MockedLazyRender(props));
+
beforeAll(() => {
originalInnerWidth = global.innerWidth;
});
@@ -372,3 +380,50 @@ describe(" card theme", () => {
expect(tree.find("GroupHeader").props().themedCounters).toBe(false);
});
});
+
+describe(" lazy rendering", () => {
+ // need to add 2x mockImplementationOnce per render since we use it twice
+ // inside each AlertGroupContent
+ const RenderPlaceholder = ({ placeholder }) => {
+ return placeholder;
+ };
+
+ it("renders FilteringLabel when visible", () => {
+ MockAlerts(5);
+ const tree = MountedAlertGroup(jest.fn(), false);
+ expect(tree.find("FilteringLabel").length).toBe(8);
+ });
+
+ it("renders GroupFooter when visible", () => {
+ MockAlerts(5);
+ const tree = MountedAlertGroup(jest.fn(), false);
+ expect(tree.find("GroupFooter").length).toBe(1);
+ });
+
+ it("renders AlertGroupPlaceholder when invisible", () => {
+ MockAlerts(5);
+ MockedLazyRender.mockImplementationOnce(
+ RenderPlaceholder
+ ).mockImplementationOnce(RenderPlaceholder);
+ const tree = MountedAlertGroup(jest.fn(), false);
+ expect(tree.find("AlertGroupPlaceholder").length).toBe(1);
+ });
+
+ it("doesn't render GroupFooter when invisible", () => {
+ MockAlerts(5);
+ MockedLazyRender.mockImplementationOnce(
+ RenderPlaceholder
+ ).mockImplementationOnce(RenderPlaceholder);
+ const tree = MountedAlertGroup(jest.fn(), false);
+ expect(tree.find("GroupFooter").length).toBe(0);
+ });
+
+ it("matches snapshot when invisible", () => {
+ MockAlerts(5);
+ MockedLazyRender.mockImplementationOnce(
+ RenderPlaceholder
+ ).mockImplementationOnce(RenderPlaceholder);
+ const tree = MountedAlertGroup(jest.fn(), false);
+ expect(toDiffableHtml(tree.html())).toMatchSnapshot();
+ });
+});