From b1c89858e809c416568ab575fc9ab58b63ce1afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sun, 14 Apr 2019 21:01:44 +0100 Subject: [PATCH] feat(ui): allow configuring grid size --- .../Components/Animations/MountFade/index.css | 14 +--- .../Components/Animations/MountFade/index.js | 2 - ui/src/Components/Grid/AlertGrid/GridSize.js | 32 ++++------ ui/src/Components/Grid/AlertGrid/index.js | 25 ++++---- .../Components/Grid/AlertGrid/index.test.js | 54 +++++++--------- .../AlertGroupWidthConfiguration.js | 64 +++++++++++++++++++ .../AlertGroupWidthConfiguration.test.js | 42 ++++++++++++ .../AlertGroupWidthConfiguration.test.js.snap | 49 ++++++++++++++ .../__snapshots__/index.test.js.snap | 45 +++++++++++++ .../MainModal/Configuration/index.js | 3 + .../MainModalContent.test.js.snap | 45 +++++++++++++ ui/src/Components/NavBar/index.test.js | 2 - ui/src/Stores/Settings.js | 3 +- 13 files changed, 301 insertions(+), 79 deletions(-) create mode 100644 ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.js create mode 100644 ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.test.js create mode 100644 ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupWidthConfiguration.test.js.snap diff --git a/ui/src/Components/Animations/MountFade/index.css b/ui/src/Components/Animations/MountFade/index.css index 37b4a1323..ae5a758ab 100644 --- a/ui/src/Components/Animations/MountFade/index.css +++ b/ui/src/Components/Animations/MountFade/index.css @@ -1,17 +1,7 @@ -.components-animation-fade-appear, -.components-animation-fade-enter { +.components-animation-fade-appear { opacity: 0.01; } -.components-animation-fade-appear-active, -.components-animation-fade-enter-active { +.components-animation-fade-appear-active { opacity: 1; transition: all 0.3s ease-in; } - -.components-animation-fade-exit { - opacity: 1; -} -.components-animation-fade-exit-active { - opacity: 0.01; - transition: all 0.3s ease-out; -} diff --git a/ui/src/Components/Animations/MountFade/index.js b/ui/src/Components/Animations/MountFade/index.js index 5ae94cf10..e7104b3af 100644 --- a/ui/src/Components/Animations/MountFade/index.js +++ b/ui/src/Components/Animations/MountFade/index.js @@ -10,8 +10,6 @@ const MountFade = ({ children, duration, ...props }) => ( classNames="components-animation-fade" timeout={300} appear={true} - enter={true} - exit={true} {...props} > {children} diff --git a/ui/src/Components/Grid/AlertGrid/GridSize.js b/ui/src/Components/Grid/AlertGrid/GridSize.js index 97eae2934..b7923e300 100644 --- a/ui/src/Components/Grid/AlertGrid/GridSize.js +++ b/ui/src/Components/Grid/AlertGrid/GridSize.js @@ -1,33 +1,25 @@ -const baseWidth = 400; - -const MinWidth = canvasWidth => - Math.floor( - baseWidth + (canvasWidth / Math.min(canvasWidth, baseWidth * 2)) * 10 - ); - // grid sizes, defines how many columns are used depending on the screen width // this is config as expected by https://github.com/callmecavs/bricks.js#sizes -const GridSizesConfig = canvasWidth => { +const GridSizesConfig = (canvasWidth, baseWidth) => { const generatedSizes = []; for (let i = 2; i < 20; i++) { generatedSizes.push({ - mq: `${i * MinWidth(i * baseWidth)}px`, + mq: `${i * baseWidth}px`, columns: i, gutter: 0 }); } - //console.info(JSON.stringify(generatedSizes)); return [...[{ columns: 1, gutter: 0 }], ...generatedSizes]; }; -const GetGridElementWidth = canvasWidth => { - const mw = MinWidth(canvasWidth); - return Math.floor( - Math.min( - mw + (canvasWidth % mw) / Math.floor(canvasWidth / mw), - canvasWidth - ) - ); -}; +const GetColumnsCount = (canvasWidth, baseWidth) => + [{ mq: "0px", columns: 1 }, ...GridSizesConfig(canvasWidth, baseWidth)] + .filter(gs => gs.mq !== undefined) + .filter(gs => canvasWidth >= Number.parseInt(gs.mq)) + .map(gs => gs.columns) + .pop(); -export { MinWidth, GridSizesConfig, GetGridElementWidth }; +const GetGridElementWidth = (canvasWidth, baseWidth) => + Math.floor(canvasWidth / GetColumnsCount(canvasWidth, baseWidth)); + +export { GridSizesConfig, GetColumnsCount, GetGridElementWidth }; diff --git a/ui/src/Components/Grid/AlertGrid/index.js b/ui/src/Components/Grid/AlertGrid/index.js index 032bc6502..5e5c350c6 100644 --- a/ui/src/Components/Grid/AlertGrid/index.js +++ b/ui/src/Components/Grid/AlertGrid/index.js @@ -42,14 +42,20 @@ const AlertGrid = observer( this.viewport = observable( { width: document.body.clientWidth, - get gridSizesConfig() { - return GridSizesConfig(this.width); - }, - get groupWidth() { - return GetGridElementWidth(this.width); - }, update() { this.width = document.body.clientWidth; + }, + get gridSizesConfig() { + return GridSizesConfig( + this.width, + props.settingsStore.gridConfig.config.groupWidth + ); + }, + get groupWidth() { + return GetGridElementWidth( + this.width, + props.settingsStore.gridConfig.config.groupWidth + ); } }, { @@ -194,12 +200,6 @@ const AlertGrid = observer( font700.load(null, 30000).then(this.masonryRepack, () => {}); } - componentDidUpdate() { - // whenever grid component re-renders we need to ensure that grid elements - // are packed correctly - this.masonryRepack(); - } - render() { const { alertStore, settingsStore, silenceFormStore } = this.props; @@ -210,6 +210,7 @@ const AlertGrid = observer( onResize={debounce(this.viewport.update, 100)} /> ", () => { expect(alertGroups).toHaveLength(80); }); - it("calls masonryRepack() after update`", () => { + it("calling masonryRepack() calls forcePack() on Masonry instance`", () => { const tree = ShallowAlertGrid(); const instance = tree.instance(); - const repackSpy = jest.spyOn(instance, "masonryRepack"); // it's a shallow render so we don't really have masonry mounted, fake it instance.masonryComponentReference.ref = { forcePack: jest.fn() }; - instance.componentDidUpdate(); - expect(repackSpy).toHaveBeenCalled(); + instance.masonryRepack(); expect(instance.masonryComponentReference.ref.forcePack).toHaveBeenCalled(); }); it("masonryRepack() doesn't crash when masonryComponentReference.ref=false`", () => { const tree = ShallowAlertGrid(); const instance = tree.instance(); - const repackSpy = jest.spyOn(instance, "masonryRepack"); instance.masonryComponentReference.ref = false; - instance.componentDidUpdate(); - expect(repackSpy).toHaveBeenCalled(); + instance.masonryRepack(); }); it("masonryRepack() doesn't crash when masonryComponentReference.ref=null`", () => { const tree = ShallowAlertGrid(); const instance = tree.instance(); - const repackSpy = jest.spyOn(instance, "masonryRepack"); instance.masonryComponentReference.ref = null; - instance.componentDidUpdate(); - expect(repackSpy).toHaveBeenCalled(); + instance.masonryRepack(); }); it("masonryRepack() doesn't crash when masonryComponentReference.ref=undefined`", () => { const tree = ShallowAlertGrid(); const instance = tree.instance(); - const repackSpy = jest.spyOn(instance, "masonryRepack"); instance.masonryComponentReference.ref = undefined; - instance.componentDidUpdate(); - expect(repackSpy).toHaveBeenCalled(); + instance.masonryRepack(); }); it("calling storeMasonryRef() saves the ref in local store", () => { @@ -345,17 +337,18 @@ describe("", () => { // known breakpoints calculated from GridSize logic [ { breakpoint: 400, columns: 1 }, - { breakpoint: 820, columns: 2 }, - { breakpoint: 1245, columns: 3 }, - { breakpoint: 1680, columns: 4 }, - { breakpoint: 2125, columns: 5 }, - { breakpoint: 2580, columns: 6 }, - { breakpoint: 3045, columns: 7 }, - { breakpoint: 3520, columns: 8 }, - { breakpoint: 4005, columns: 9 }, - { breakpoint: 4500, 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 } ].map(t => it(`renders ${t.columns} column(s) on ${t.breakpoint} 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); @@ -369,24 +362,25 @@ describe("", () => { { canvas: 1280, columns: 3 }, { canvas: 1366, columns: 3 }, { canvas: 1440, columns: 3 }, - { canvas: 1600, columns: 3 }, - { canvas: 1680, columns: 3 }, + { canvas: 1600, columns: 4 }, + { canvas: 1680, columns: 4 }, { canvas: 1920, columns: 4 }, - { canvas: 2048, columns: 4 }, - { canvas: 2560, columns: 5 }, - { canvas: 3840, columns: 8 } + { canvas: 2048, columns: 5 }, + { canvas: 2560, columns: 6 }, + { canvas: 3840, columns: 9 } ].map(t => it(`renders ${t.columns} column(s) with ${t.canvas} resolution`, () => { + settingsStore.gridConfig.config.groupWidth = 400; VerifyColumnCount(t.canvas, t.columns); }) ); it("renders expected number of columns for every resolution", () => { + const minWidth = 400; let lastColumns = 1; for (let i = 100; i <= 4096; i++) { - const minWidth = MinWidth(i); const expectedColumns = Math.max(Math.floor(i / minWidth), 1); - const columns = Math.floor(i / GetGridElementWidth(i)); + const columns = Math.floor(i / GetGridElementWidth(i, minWidth)); expect({ resolution: i, diff --git a/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.js b/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.js new file mode 100644 index 000000000..87aefdf59 --- /dev/null +++ b/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.js @@ -0,0 +1,64 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; + +import { observable, action, toJS } from "mobx"; +import { observer } from "mobx-react"; + +import { debounce } from "lodash"; + +import InputRange from "react-input-range"; + +import { Settings } from "Stores/Settings"; + +import "./InputRange.scss"; + +const AlertGroupWidthConfiguration = observer( + class AlertGroupWidthConfiguration extends Component { + static propTypes = { + settingsStore: PropTypes.instanceOf(Settings).isRequired + }; + + constructor(props) { + super(props); + + this.config = observable({ + groupWidth: toJS(props.settingsStore.gridConfig.config.groupWidth) + }); + } + + onChange = action(value => { + this.config.groupWidth = value; + }); + + onChangeComplete = debounce( + action(value => { + const { settingsStore } = this.props; + + settingsStore.gridConfig.config.groupWidth = value; + }), + 200 + ); + + render() { + return ( +
+ + +
+ ); + } + } +); + +export { AlertGroupWidthConfiguration }; diff --git a/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.test.js b/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.test.js new file mode 100644 index 000000000..a8f85d773 --- /dev/null +++ b/ui/src/Components/MainModal/Configuration/AlertGroupWidthConfiguration.test.js @@ -0,0 +1,42 @@ +import React from "react"; + +import { mount } from "enzyme"; + +import toDiffableHtml from "diffable-html"; + +import { Settings } from "Stores/Settings"; +import { AlertGroupWidthConfiguration } from "./AlertGroupWidthConfiguration"; + +let settingsStore; +beforeEach(() => { + settingsStore = new Settings(); +}); + +const FakeConfiguration = () => { + return mount(); +}; + +describe("", () => { + it("matches snapshot with default values", () => { + const tree = FakeConfiguration(); + expect(toDiffableHtml(tree.html())).toMatchSnapshot(); + }); + + it("call to onChange() updates internal state", () => { + const tree = FakeConfiguration(); + tree.instance().onChange(500); + expect(tree.instance().config.groupWidth).toBe(500); + }); + + it("settings are updated on completed change", () => { + const tree = FakeConfiguration(); + tree.instance().onChangeComplete(555); + expect(settingsStore.gridConfig.config.groupWidth).toBe(555); + }); + + it("custom interval value is rendered correctly", () => { + settingsStore.gridConfig.config.groupWidth = 455; + const component = FakeConfiguration(); + expect(component.find("InputRange").props().value).toBe(455); + }); +}); diff --git a/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupWidthConfiguration.test.js.snap b/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupWidthConfiguration.test.js.snap new file mode 100644 index 000000000..55b020c4f --- /dev/null +++ b/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupWidthConfiguration.test.js.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` matches snapshot with default values 1`] = ` +" +
+ +
+ + + 300 + + +
+
+
+ + + + 420 + + +
+
+
+
+ + + 800 + + +
+
+" +`; diff --git a/ui/src/Components/MainModal/Configuration/__snapshots__/index.test.js.snap b/ui/src/Components/MainModal/Configuration/__snapshots__/index.test.js.snap index 12da2f170..5f0f81a6f 100644 --- a/ui/src/Components/MainModal/Configuration/__snapshots__/index.test.js.snap +++ b/ui/src/Components/MainModal/Configuration/__snapshots__/index.test.js.snap @@ -72,6 +72,51 @@ exports[` matches snapshot 1`] = `
+
+ +
+ + + 300 + + +
+
+
+ + + + 420 + + +
+
+
+
+ + + 800 + + +
+
+
+