From 9b78c96e1e1733b19407337dedb34a30ba9f5d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Wed, 2 Oct 2019 19:21:12 +0100 Subject: [PATCH] fix(ui): better handling of window resize events --- ui/src/Components/Grid/AlertGrid/GridSize.js | 4 +- ui/src/Components/Grid/AlertGrid/index.js | 65 ++++----- .../Components/Grid/AlertGrid/index.test.js | 123 ++++++++++-------- ui/src/Components/Grid/index.stories.js | 1 - 4 files changed, 96 insertions(+), 97 deletions(-) diff --git a/ui/src/Components/Grid/AlertGrid/GridSize.js b/ui/src/Components/Grid/AlertGrid/GridSize.js index b7923e300..59f0e078e 100644 --- a/ui/src/Components/Grid/AlertGrid/GridSize.js +++ b/ui/src/Components/Grid/AlertGrid/GridSize.js @@ -19,7 +19,7 @@ const GetColumnsCount = (canvasWidth, baseWidth) => .map(gs => gs.columns) .pop(); -const GetGridElementWidth = (canvasWidth, baseWidth) => - Math.floor(canvasWidth / GetColumnsCount(canvasWidth, baseWidth)); +const GetGridElementWidth = (innerWidth, outerWidth, baseWidth) => + Math.floor(innerWidth / GetColumnsCount(outerWidth, baseWidth)); export { GridSizesConfig, GetColumnsCount, GetGridElementWidth }; diff --git a/ui/src/Components/Grid/AlertGrid/index.js b/ui/src/Components/Grid/AlertGrid/index.js index 5fd5f07e7..df40d9bdb 100644 --- a/ui/src/Components/Grid/AlertGrid/index.js +++ b/ui/src/Components/Grid/AlertGrid/index.js @@ -39,61 +39,38 @@ const AlertGrid = observer( // and group size this.viewport = observable( { - width: document.body.clientWidth, - widthAdjust: 0, - widthHistory: [], - update(width, height) { - if ( - this.widthHistory.length === 4 && - this.widthHistory[0] !== this.widthHistory[1] && - this.widthHistory[0] !== this.widthHistory[3] - ) { - const uniqueWidths = this.widthHistory.reduce((uniques, w) => { - const count = uniques[w] || 0; - uniques[w] = count + 1; - return uniques; - }, {}); - - if ( - this.widthHistory.includes(width) && - Object.keys(uniqueWidths).length === 2 && - Object.values(uniqueWidths)[0] === - Object.values(uniqueWidths)[1] - ) { - this.widthAdjust = Math.min(this.widthAdjust + 20, 200); - } else { - this.widthAdjust = 0; - } - } - - this.width = width; - - this.widthHistory.unshift(width); - this.widthHistory = this.widthHistory.slice(0, 4); + canvasWidth: document.body.clientWidth, + windowWidth: window.innerWidth, + updateWidths(canvasWidth, windowWidth) { + this.canvasWidth = canvasWidth; + this.windowWidth = windowWidth; }, get gridSizesConfig() { return GridSizesConfig( - this.width, - props.settingsStore.gridConfig.config.groupWidth + - this.widthAdjust + this.windowWidth, + props.settingsStore.gridConfig.config.groupWidth ); }, get groupWidth() { return GetGridElementWidth( - this.width, - props.settingsStore.gridConfig.config.groupWidth + - this.widthAdjust + this.canvasWidth, + this.windowWidth, + props.settingsStore.gridConfig.config.groupWidth ); } }, { - update: action.bound, + updateWidths: action.bound, gridSizesConfig: computed, groupWidth: computed } ); } + handleResize = debounce(() => { + 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 @@ -153,6 +130,12 @@ const AlertGrid = observer( // wait up to 30s, run no-op function on timeout font.load(null, 30000).then(this.masonryRepack, () => {}); } + + window.addEventListener("resize", this.handleResize); + } + + componentWillUnmount() { + window.removeEventListener("resize", this.handleResize); } render() { @@ -163,13 +146,9 @@ const AlertGrid = observer( { alertStore.data.groups = groups; }; -const VerifyColumnCount = (innerWidth, columns) => { +const VerifyColumnCount = (innerWidth, outerWidth, columns) => { MockGroupList(60, 5); const tree = ShallowAlertGrid(); - tree.instance().viewport.update(innerWidth, 500); + tree.instance().viewport.updateWidths(innerWidth, outerWidth); expect( tree .find("AlertGroup") @@ -167,22 +167,22 @@ describe("", () => { // known breakpoints calculated from GridSize logic [ - { breakpoint: 400, columns: 1 }, - { breakpoint: 800, columns: 2 }, - { breakpoint: 1200, columns: 3 }, - { breakpoint: 1600, columns: 4 }, - { breakpoint: 2000, columns: 5 }, - { breakpoint: 2400, columns: 6 }, - { breakpoint: 3000, columns: 7 }, - { breakpoint: 3400, columns: 8 }, - { breakpoint: 3800, columns: 9 }, - { breakpoint: 4200, columns: 10 } + { canvas: 400, columns: 1 }, + { canvas: 800, columns: 2 }, + { canvas: 1200, columns: 3 }, + { canvas: 1600, columns: 4 }, + { canvas: 2000, columns: 5 }, + { canvas: 2400, columns: 6 }, + { canvas: 2800, columns: 7 }, + { canvas: 3200, columns: 8 }, + { canvas: 3600, columns: 9 }, + { canvas: 4000, columns: 10 } ].map(t => - it(`renders ${t.columns} column(s) on ${t.breakpoint} breakpoint`, () => { + it(`renders ${t.columns} column(s) on ${t.canvas} breakpoint`, () => { settingsStore.gridConfig.config.groupWidth = 400; - VerifyColumnCount(t.canvas - 1, Math.max(1, t.columns - 1)); - VerifyColumnCount(t.canvas, t.columns); - VerifyColumnCount(t.canvas + 1, t.columns); + VerifyColumnCount(t.canvas - 1, t.canvas - 1, Math.max(1, t.columns - 1)); + VerifyColumnCount(t.canvas, t.canvas, t.columns); + VerifyColumnCount(t.canvas + 1, t.canvas + 1, t.columns); }) ); @@ -202,7 +202,7 @@ describe("", () => { ].map(t => it(`renders ${t.columns} column(s) with ${t.canvas} resolution`, () => { settingsStore.gridConfig.config.groupWidth = 400; - VerifyColumnCount(t.canvas, t.columns); + VerifyColumnCount(t.canvas, t.canvas, t.columns); }) ); @@ -211,7 +211,7 @@ describe("", () => { let lastColumns = 1; for (let i = 100; i <= 4096; i++) { const expectedColumns = Math.max(Math.floor(i / minWidth), 1); - const columns = Math.floor(i / GetGridElementWidth(i, minWidth)); + const columns = Math.floor(i / GetGridElementWidth(i, i, minWidth)); expect({ resolution: i, @@ -234,7 +234,7 @@ describe("", () => { MockGroupList(60, 5); const tree = ShallowAlertGrid(); // set initial width - tree.instance().viewport.update(1980, 500); + tree.instance().viewport.updateWidths(1980, 1980); expect( tree .find("AlertGroup") @@ -243,7 +243,7 @@ describe("", () => { ).toBe(1980 / 4); // then resize and verify if column count was changed - tree.instance().viewport.update(1000, 500); + tree.instance().viewport.updateWidths(1000, 1000); expect( tree .find("AlertGroup") @@ -252,14 +252,50 @@ describe("", () => { ).toBe(1000 / 2); }); + it("scrollbar render doesn't resize alert groups", () => { + settingsStore.gridConfig.config.groupWidth = 400; + + MockGroupList(60, 5); + const tree = ShallowAlertGrid(); + // set initial width + tree.instance().viewport.updateWidths(1600, 1600); + 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); + expect( + tree + .find("AlertGroup") + .at(0) + .props().style.width + ).toBe(396); + }); + + it("window resize event calls updateWidths", () => { + MockGroupList(60, 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 = 410; + settingsStore.gridConfig.config.groupWidth = 400; const tree = ShallowAlertGrid(); let results = []; for (var index = 0; index < 14; index++) { MockGroupList(60, 5); - tree.instance().viewport.update(index % 2 === 0 ? 800 : 830, 500); + tree + .instance() + .viewport.updateWidths(index % 2 === 0 ? 1600 : 1584, 1600); results.push( tree .find("AlertGroup") @@ -268,37 +304,22 @@ describe("", () => { ); } - // first 4 results will switch beween 1 and 2 columns, but after than it - // should stabilise and return same result as the grid width expect(results).toStrictEqual([ - 800, - 415, - 800, - 415, - 800, - 830, - 800, - 830, - 800, - 830, - 800, - 830, - 800, - 830 + 400, + 396, + 400, + 396, + 400, + 396, + 400, + 396, + 400, + 396, + 400, + 396, + 400, + 396 ]); - - // so now let's call it without any loop - results = []; - for (let width of [840, 820, 450, 450, 1200]) { - tree.instance().viewport.update(width, 500); - results.push( - tree - .find("AlertGroup") - .at(0) - .props().style.width - ); - } - expect(results).toStrictEqual([420, 410, 450, 450, 600]); }); it("doesn't crash on unmount", () => { diff --git a/ui/src/Components/Grid/index.stories.js b/ui/src/Components/Grid/index.stories.js index 769a6d1db..27db27e61 100644 --- a/ui/src/Components/Grid/index.stories.js +++ b/ui/src/Components/Grid/index.stories.js @@ -73,7 +73,6 @@ const MockGroup = (groupName, alertCount, active, suppressed, unprocessed) => { }; storiesOf("Grid", module) - .addDecorator(storyFn =>
{storyFn()}
) .add("UpstreamError", () => { return ; })