From 310bbdf54ba327d3e2a87fdbb851aa11954ebdee Mon Sep 17 00:00:00 2001 From: Victor Duarte Date: Thu, 17 Jun 2021 13:20:39 -0500 Subject: [PATCH] fix(client): store challenge panes sizes (#42519) Co-authored-by: Oliver Eyton-Williams --- .../Challenges/classic/DesktopLayout.js | 46 ++++++++++++++-- .../src/templates/Challenges/classic/Show.js | 54 ++++++++++++++++++- client/src/utils/is-contained.test.ts | 15 ++++++ client/src/utils/is-contained.ts | 4 ++ 4 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 client/src/utils/is-contained.test.ts create mode 100644 client/src/utils/is-contained.ts diff --git a/client/src/templates/Challenges/classic/DesktopLayout.js b/client/src/templates/Challenges/classic/DesktopLayout.js index 886473425f..fbab59d40d 100644 --- a/client/src/templates/Challenges/classic/DesktopLayout.js +++ b/client/src/templates/Challenges/classic/DesktopLayout.js @@ -8,12 +8,23 @@ import envData from '../../../../../config/env.json'; const { showUpcomingChanges } = envData; +const paneType = { + flex: PropTypes.number +}; + const propTypes = { challengeFiles: PropTypes.object, editor: PropTypes.element, hasEditableBoundries: PropTypes.bool, hasPreview: PropTypes.bool, instructions: PropTypes.element, + layoutState: PropTypes.shape({ + codePane: paneType, + editorPane: paneType, + instructionPane: paneType, + previewPane: paneType, + testsPane: paneType + }), preview: PropTypes.element, resizeProps: PropTypes.shape({ onStopResize: PropTypes.func, @@ -55,6 +66,7 @@ class DesktopLayout extends Component { editor, testOutput, hasPreview, + layoutState, preview, hasEditableBoundries } = this.props; @@ -67,6 +79,8 @@ class DesktopLayout extends Component { ? showPreview && hasPreview : hasPreview; const isConsoleDisplayable = projectBasedChallenge ? showConsole : true; + const { codePane, editorPane, instructionPane, previewPane, testsPane } = + layoutState; return ( @@ -75,7 +89,11 @@ class DesktopLayout extends Component { )} {!projectBasedChallenge && ( - + {instructions} )} @@ -83,20 +101,34 @@ class DesktopLayout extends Component { )} - + {challengeFile && showUpcomingChanges && !hasEditableBoundries && ( )} {challengeFile && ( - + {{editor}} {isConsoleDisplayable && ( )} {isConsoleDisplayable && ( - + {testOutput} )} @@ -107,7 +139,11 @@ class DesktopLayout extends Component { )} {isPreviewDisplayable && ( - + {preview} )} diff --git a/client/src/templates/Challenges/classic/Show.js b/client/src/templates/Challenges/classic/Show.js index 873966fa64..44581370a9 100644 --- a/client/src/templates/Challenges/classic/Show.js +++ b/client/src/templates/Challenges/classic/Show.js @@ -22,7 +22,9 @@ import DesktopLayout from './DesktopLayout'; import Hotkeys from '../components/Hotkeys'; import { getGuideUrl } from '../utils'; +import store from 'store'; import { challengeTypes } from '../../../../utils/challengeTypes'; +import { isContained } from '../../../utils/is-contained'; import { ChallengeNode } from '../../../redux/prop-types'; import { createFiles, @@ -92,6 +94,24 @@ const propTypes = { }; const MAX_MOBILE_WIDTH = 767; +const REFLEX_LAYOUT = 'challenge-layout'; +const BASE_LAYOUT = { + codePane: { + flex: 1 + }, + editorPane: { + flex: 1 + }, + instructionPane: { + flex: 1 + }, + previewPane: { + flex: 0.7 + }, + testsPane: { + flex: 0.25 + } +}; class ShowClassic extends Component { constructor() { @@ -108,13 +128,44 @@ class ShowClassic extends Component { this.containerRef = React.createRef(); this.editorRef = React.createRef(); + // Holds the information of the panes sizes for desktop view + this.layoutState = this.getLayoutState(); } + + getLayoutState() { + const reflexLayout = store.get(REFLEX_LAYOUT); + + // Validate if user has not done any resize of the panes + if (!reflexLayout) return BASE_LAYOUT; + + // Check that the layout values stored are valid (exist in base layout). If + // not valid, it will fallback to the base layout values and be set on next + // user resize. + const isValidLayout = isContained( + Object.keys(BASE_LAYOUT), + Object.keys(reflexLayout) + ); + + return isValidLayout ? reflexLayout : BASE_LAYOUT; + } + onResize() { this.setState({ resizing: true }); } - onStopResize() { + onStopResize(event) { + const { name, flex } = event.component.props; + this.setState({ resizing: false }); + + // Only interested in tracking layout updates for ReflexElement's + if (!name) { + return; + } + + this.layoutState[name].flex = flex; + + store.set(REFLEX_LAYOUT, this.layoutState); } componentDidMount() { @@ -325,6 +376,7 @@ class ShowClassic extends Component { instructions={this.renderInstructionsPanel({ showToolPanel: true })} + layoutState={this.layoutState} preview={this.renderPreview()} resizeProps={this.resizeProps} testOutput={this.renderTestOutput()} diff --git a/client/src/utils/is-contained.test.ts b/client/src/utils/is-contained.test.ts new file mode 100644 index 0000000000..14fd0d1905 --- /dev/null +++ b/client/src/utils/is-contained.test.ts @@ -0,0 +1,15 @@ +import { isContained } from './is-contained'; + +describe('client/src isContained', () => { + it('returns true if `arr1` values are contained in `arr2`', () => { + const arr1 = ['dog', 'cat']; + const arr2 = ['cat', 'dog']; + expect(isContained(arr1, arr2)).toEqual(true); + }); + + it('returns true if `arr1` values are not contained in `arr2`', () => { + const arr1 = ['dog', 'cat']; + const arr2 = ['cat', 'monkey', 'bird']; + expect(isContained(arr1, arr2)).toEqual(false); + }); +}); diff --git a/client/src/utils/is-contained.ts b/client/src/utils/is-contained.ts new file mode 100644 index 0000000000..c25fd2253f --- /dev/null +++ b/client/src/utils/is-contained.ts @@ -0,0 +1,4 @@ +// Performs a check if the items in `value` exist in `other` +export function isContained(value: string[], other: string[]): boolean { + return value.every(i => other.includes(i)); +}