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 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 (
<Fragment>
@ -75,7 +89,11 @@ class DesktopLayout extends Component {
)}
<ReflexContainer className='desktop-layout' orientation='vertical'>
{!projectBasedChallenge && (
<ReflexElement flex={1} {...resizeProps}>
<ReflexElement
flex={instructionPane.flex}
name='instructionPane'
{...resizeProps}
>
{instructions}
</ReflexElement>
)}
@ -83,20 +101,34 @@ class DesktopLayout extends Component {
<ReflexSplitter propagate={true} {...resizeProps} />
)}
<ReflexElement flex={1} {...resizeProps}>
<ReflexElement
flex={editorPane.flex}
name='editorPane'
{...resizeProps}
>
{challengeFile && showUpcomingChanges && !hasEditableBoundries && (
<EditorTabs />
)}
{challengeFile && (
<ReflexContainer key={challengeFile.key} orientation='horizontal'>
<ReflexElement flex={1} {...reflexProps} {...resizeProps}>
<ReflexElement
flex={codePane.flex}
name='codePane'
{...reflexProps}
{...resizeProps}
>
{<Fragment>{editor}</Fragment>}
</ReflexElement>
{isConsoleDisplayable && (
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isConsoleDisplayable && (
<ReflexElement flex={0.25} {...reflexProps} {...resizeProps}>
<ReflexElement
flex={testsPane.flex}
name='testsPane'
{...reflexProps}
{...resizeProps}
>
{testOutput}
</ReflexElement>
)}
@ -107,7 +139,11 @@ class DesktopLayout extends Component {
<ReflexSplitter propagate={true} {...resizeProps} />
)}
{isPreviewDisplayable && (
<ReflexElement flex={0.7} {...resizeProps}>
<ReflexElement
flex={previewPane.flex}
name='previewPane'
{...resizeProps}
>
{preview}
</ReflexElement>
)}

View File

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

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