fix(client): store challenge panes sizes (#42519)

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Victor Duarte
2021-06-17 13:20:39 -05:00
committed by GitHub
parent 3a8c1444eb
commit 310bbdf54b
4 changed files with 113 additions and 6 deletions

View File

@ -8,12 +8,23 @@ import envData from '../../../../../config/env.json';
const { showUpcomingChanges } = envData; const { showUpcomingChanges } = envData;
const paneType = {
flex: PropTypes.number
};
const propTypes = { const propTypes = {
challengeFiles: PropTypes.object, challengeFiles: PropTypes.object,
editor: PropTypes.element, editor: PropTypes.element,
hasEditableBoundries: PropTypes.bool, hasEditableBoundries: PropTypes.bool,
hasPreview: PropTypes.bool, hasPreview: PropTypes.bool,
instructions: PropTypes.element, instructions: PropTypes.element,
layoutState: PropTypes.shape({
codePane: paneType,
editorPane: paneType,
instructionPane: paneType,
previewPane: paneType,
testsPane: paneType
}),
preview: PropTypes.element, preview: PropTypes.element,
resizeProps: PropTypes.shape({ resizeProps: PropTypes.shape({
onStopResize: PropTypes.func, onStopResize: PropTypes.func,
@ -55,6 +66,7 @@ class DesktopLayout extends Component {
editor, editor,
testOutput, testOutput,
hasPreview, hasPreview,
layoutState,
preview, preview,
hasEditableBoundries hasEditableBoundries
} = this.props; } = this.props;
@ -67,6 +79,8 @@ class DesktopLayout extends Component {
? showPreview && hasPreview ? showPreview && hasPreview
: hasPreview; : hasPreview;
const isConsoleDisplayable = projectBasedChallenge ? showConsole : true; const isConsoleDisplayable = projectBasedChallenge ? showConsole : true;
const { codePane, editorPane, instructionPane, previewPane, testsPane } =
layoutState;
return ( return (
<Fragment> <Fragment>
@ -75,7 +89,11 @@ class DesktopLayout extends Component {
)} )}
<ReflexContainer className='desktop-layout' orientation='vertical'> <ReflexContainer className='desktop-layout' orientation='vertical'>
{!projectBasedChallenge && ( {!projectBasedChallenge && (
<ReflexElement flex={1} {...resizeProps}> <ReflexElement
flex={instructionPane.flex}
name='instructionPane'
{...resizeProps}
>
{instructions} {instructions}
</ReflexElement> </ReflexElement>
)} )}
@ -83,20 +101,34 @@ class DesktopLayout extends Component {
<ReflexSplitter propagate={true} {...resizeProps} /> <ReflexSplitter propagate={true} {...resizeProps} />
)} )}
<ReflexElement flex={1} {...resizeProps}> <ReflexElement
flex={editorPane.flex}
name='editorPane'
{...resizeProps}
>
{challengeFile && showUpcomingChanges && !hasEditableBoundries && ( {challengeFile && showUpcomingChanges && !hasEditableBoundries && (
<EditorTabs /> <EditorTabs />
)} )}
{challengeFile && ( {challengeFile && (
<ReflexContainer key={challengeFile.key} orientation='horizontal'> <ReflexContainer key={challengeFile.key} orientation='horizontal'>
<ReflexElement flex={1} {...reflexProps} {...resizeProps}> <ReflexElement
flex={codePane.flex}
name='codePane'
{...reflexProps}
{...resizeProps}
>
{<Fragment>{editor}</Fragment>} {<Fragment>{editor}</Fragment>}
</ReflexElement> </ReflexElement>
{isConsoleDisplayable && ( {isConsoleDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} /> <ReflexSplitter propagate={true} {...resizeProps} />
)} )}
{isConsoleDisplayable && ( {isConsoleDisplayable && (
<ReflexElement flex={0.25} {...reflexProps} {...resizeProps}> <ReflexElement
flex={testsPane.flex}
name='testsPane'
{...reflexProps}
{...resizeProps}
>
{testOutput} {testOutput}
</ReflexElement> </ReflexElement>
)} )}
@ -107,7 +139,11 @@ class DesktopLayout extends Component {
<ReflexSplitter propagate={true} {...resizeProps} /> <ReflexSplitter propagate={true} {...resizeProps} />
)} )}
{isPreviewDisplayable && ( {isPreviewDisplayable && (
<ReflexElement flex={0.7} {...resizeProps}> <ReflexElement
flex={previewPane.flex}
name='previewPane'
{...resizeProps}
>
{preview} {preview}
</ReflexElement> </ReflexElement>
)} )}

View File

@ -22,7 +22,9 @@ import DesktopLayout from './DesktopLayout';
import Hotkeys from '../components/Hotkeys'; import Hotkeys from '../components/Hotkeys';
import { getGuideUrl } from '../utils'; import { getGuideUrl } from '../utils';
import store from 'store';
import { challengeTypes } from '../../../../utils/challengeTypes'; import { challengeTypes } from '../../../../utils/challengeTypes';
import { isContained } from '../../../utils/is-contained';
import { ChallengeNode } from '../../../redux/prop-types'; import { ChallengeNode } from '../../../redux/prop-types';
import { import {
createFiles, createFiles,
@ -92,6 +94,24 @@ const propTypes = {
}; };
const MAX_MOBILE_WIDTH = 767; 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 { class ShowClassic extends Component {
constructor() { constructor() {
@ -108,13 +128,44 @@ class ShowClassic extends Component {
this.containerRef = React.createRef(); this.containerRef = React.createRef();
this.editorRef = 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() { onResize() {
this.setState({ resizing: true }); this.setState({ resizing: true });
} }
onStopResize() { onStopResize(event) {
const { name, flex } = event.component.props;
this.setState({ resizing: false }); 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() { componentDidMount() {
@ -325,6 +376,7 @@ class ShowClassic extends Component {
instructions={this.renderInstructionsPanel({ instructions={this.renderInstructionsPanel({
showToolPanel: true showToolPanel: true
})} })}
layoutState={this.layoutState}
preview={this.renderPreview()} preview={this.renderPreview()}
resizeProps={this.resizeProps} resizeProps={this.resizeProps}
testOutput={this.renderTestOutput()} testOutput={this.renderTestOutput()}

View File

@ -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);
});
});

View File

@ -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));
}