Skip to content

Commit 62f2d69

Browse files
remo5000ning-y
authored andcommitted
Fix workspace bugs (#173)
* Fix #164 * Fix #153 * Fix #167 Adding this infinity prop is part of an update we do not have yet (ace editor) fxmontigny/ng2-ace-editor#11 Used a fix for react I found here: securingsincity/react-ace#29 * Fix #172, #171, #168 using PureComponent - Call scroll inside ReplInput instead of Repl - Change components to PureComponents (thereby changing the update condition) - Remove throttle for onChange Lack of unneccasry updates and proper scrolling mechanism fixed #168. * Format files * Update tests * Move overflow to side-content-text Also fixed a minor issue with padding disappearing, using fit-content. * Remove text justification for markdown editor I don't think markdown is justified, and so we shouln't be displaying it in such a way either. * Fix always-on scrollbars on X11 * Add overflow-y for card * Fix side content header height Also moved the css into the appropriate nested location. * Format scss * Bump version number 0.1.2 -> 0.1.3
1 parent 6a54166 commit 62f2d69

File tree

11 files changed

+105
-96
lines changed

11 files changed

+105
-96
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"name": "cadet-frontend",
4-
"version": "0.1.2",
4+
"version": "0.1.3",
55
"scripts-info": {
66
"format": "Format source code",
77
"start": "Start the Webpack development server",

src/components/assessment/AssessmentWorkspace.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,14 @@ class AssessmentWorkspace extends React.Component<
8484
</Card>
8585
</Dialog>
8686
)
87-
const question: IQuestion = this.props.assessment.questions[this.props.questionId]
87+
/* If questionId is out of bounds, set it to the max. */
88+
const questionId =
89+
this.props.questionId >= this.props.assessment.questions.length
90+
? this.props.assessment.questions.length - 1
91+
: this.props.questionId
92+
const question: IQuestion = this.props.assessment.questions[questionId]
8893
const workspaceProps: WorkspaceProps = {
89-
controlBarProps: this.controlBarProps(this.props),
94+
controlBarProps: this.controlBarProps(this.props, questionId),
9095
editorProps:
9196
question.type === QuestionTypes.programming
9297
? {
@@ -103,7 +108,7 @@ class AssessmentWorkspace extends React.Component<
103108
handleSideContentHeightChange: this.props.handleSideContentHeightChange,
104109
mcq: question as IMCQQuestion,
105110
sideContentHeight: this.props.sideContentHeight,
106-
sideContentProps: this.sideContentProps(this.props),
111+
sideContentProps: this.sideContentProps(this.props, questionId),
107112
replProps: {
108113
output: this.props.output,
109114
replValue: this.props.replValue,
@@ -120,16 +125,17 @@ class AssessmentWorkspace extends React.Component<
120125
}
121126

122127
/** Pre-condition: IAssessment has been loaded */
123-
private sideContentProps: (p: AssessmentWorkspaceProps) => SideContentProps = (
124-
props: AssessmentWorkspaceProps
128+
private sideContentProps: (p: AssessmentWorkspaceProps, q: number) => SideContentProps = (
129+
props: AssessmentWorkspaceProps,
130+
questionId: number
125131
) => ({
126132
activeTab: props.activeTab,
127133
handleChangeActiveTab: props.handleChangeActiveTab,
128134
tabs: [
129135
{
130-
label: `Task ${props.questionId}`,
136+
label: `Task ${questionId}`,
131137
icon: IconNames.NINJA,
132-
body: <Text> {props.assessment!.questions[props.questionId].content} </Text>
138+
body: <Text> {props.assessment!.questions[questionId].content} </Text>
133139
},
134140
{
135141
label: `${props.assessment!.category} Briefing`,
@@ -140,8 +146,9 @@ class AssessmentWorkspace extends React.Component<
140146
})
141147

142148
/** Pre-condition: IAssessment has been loaded */
143-
private controlBarProps: (p: AssessmentWorkspaceProps) => ControlBarProps = (
144-
props: AssessmentWorkspaceProps
149+
private controlBarProps: (p: AssessmentWorkspaceProps, q: number) => ControlBarProps = (
150+
props: AssessmentWorkspaceProps,
151+
questionId: number
145152
) => {
146153
const listingPath = `/academy/${assessmentCategoryLink(this.props.assessment!.category)}`
147154
const assessmentWorkspacePath = listingPath + `/${this.props.assessment!.id.toString()}`
@@ -152,16 +159,15 @@ class AssessmentWorkspace extends React.Component<
152159
handleReplEval: this.props.handleReplEval,
153160
handleReplOutputClear: this.props.handleReplOutputClear,
154161
hasChapterSelect: false,
155-
hasNextButton: this.props.questionId < this.props.assessment!.questions.length - 1,
156-
hasPreviousButton: this.props.questionId > 0,
162+
hasNextButton: questionId < this.props.assessment!.questions.length - 1,
163+
hasPreviousButton: questionId > 0,
157164
hasSaveButton: true,
158165
hasShareButton: false,
159-
hasSubmitButton: this.props.questionId === this.props.assessment!.questions.length - 1,
166+
hasSubmitButton: questionId === this.props.assessment!.questions.length - 1,
160167
isRunning: this.props.isRunning,
161-
onClickNext: () =>
162-
history.push(assessmentWorkspacePath + `/${(this.props.questionId + 1).toString()}`),
168+
onClickNext: () => history.push(assessmentWorkspacePath + `/${(questionId + 1).toString()}`),
163169
onClickPrevious: () =>
164-
history.push(assessmentWorkspacePath + `/${(this.props.questionId - 1).toString()}`),
170+
history.push(assessmentWorkspacePath + `/${(questionId - 1).toString()}`),
165171
onClickSubmit: () => history.push(listingPath),
166172
sourceChapter: 2 // TODO dynamic library changing
167173
}

src/components/workspace/ControlBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ interface IChapter {
3434
displayName: string
3535
}
3636

37-
class ControlBar extends React.Component<ControlBarProps, {}> {
37+
class ControlBar extends React.PureComponent<ControlBarProps, {}> {
3838
public static defaultProps: Partial<ControlBarProps> = {
3939
hasChapterSelect: false,
4040
hasNextButton: false,

src/components/workspace/Editor.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,13 @@ export interface IEditorProps {
1818
handleEditorValueChange: (newCode: string) => void
1919
}
2020

21-
class Editor extends React.Component<IEditorProps, {}> {
21+
class Editor extends React.PureComponent<IEditorProps, {}> {
2222
public render() {
2323
return (
2424
<HotKeys className="Editor" handlers={handlers}>
2525
<div className="row editor-react-ace">
2626
<AceEditor
2727
className="react-ace"
28-
mode="javascript"
29-
theme="cobalt"
30-
value={this.props.editorValue}
31-
onChange={this.props.handleEditorValueChange}
32-
height="100%"
3328
commands={[
3429
{
3530
name: 'evaluate',
@@ -40,9 +35,17 @@ class Editor extends React.Component<IEditorProps, {}> {
4035
exec: this.props.handleEditorEval
4136
}
4237
]}
43-
width="100%"
38+
editorProps={{
39+
$blockScrolling: Infinity
40+
}}
4441
fontSize={14}
42+
height="100%"
4543
highlightActiveLine={false}
44+
mode="javascript"
45+
onChange={this.props.handleEditorValueChange}
46+
theme="cobalt"
47+
value={this.props.editorValue}
48+
width="100%"
4649
/>
4750
</div>
4851
</HotKeys>

src/components/workspace/MCQChooser.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ export interface IMCQChooserProps {
88
mcqSubmit?: (choiceId: number) => void
99
}
1010

11-
class MCQChooser extends React.Component<IMCQChooserProps, {}> {
11+
class MCQChooser extends React.PureComponent<IMCQChooserProps, {}> {
1212
public render() {
1313
const mockMcqSubmit = (i: number) => () => {}
1414
const options = this.props.mcq.choices.map((choice, i) => (
15-
<Button className="mcq-option col-xs-6" onClick={mockMcqSubmit(i)}>
16-
<Tooltip key={i} content={choice.hint}>
15+
<Button key={i} className="mcq-option col-xs-6" onClick={mockMcqSubmit(i)}>
16+
<Tooltip content={choice.hint}>
1717
<Text className="Text"> {choice.content} </Text>
1818
</Tooltip>
1919
</Button>

src/components/workspace/Repl.tsx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,7 @@ export interface IOutputProps {
1717
output: InterpreterOutput
1818
}
1919

20-
class Repl extends React.Component<IReplProps, {}> {
21-
private replBottom: HTMLDivElement
22-
23-
public componentDidUpdate() {
24-
if (this.replBottom.clientWidth >= window.innerWidth - 50) {
25-
/* There is a bug where
26-
* if the workspace has been resized via re-resizable such that the
27-
* has disappeared off the screen, width 63
28-
* then
29-
* calling scrollIntoView would cause the Repl to suddenly take up 100%
30-
* of the screen width. This pushes the editor off-screen so that the
31-
* user can no longer resize the workspace at all
32-
* Fix: the if condition is true when the Repl has dissapeared off-screen.
33-
* (-15 to account for the scrollbar */
34-
} else {
35-
this.replBottom.scrollIntoView()
36-
}
37-
}
38-
20+
class Repl extends React.PureComponent<IReplProps, {}> {
3921
public render() {
4022
const cards = this.props.output.map((slice, index) => <Output output={slice} key={index} />)
4123
const inputProps: IReplInputProps = this.props as IReplInputProps
@@ -46,7 +28,6 @@ class Repl extends React.Component<IReplProps, {}> {
4628
<HotKeys className="repl-input-parent row pt-card pt-elevation-0" handlers={handlers}>
4729
<ReplInput {...inputProps} />
4830
</HotKeys>
49-
<div ref={e => (this.replBottom = e!)} />
5031
</div>
5132
</div>
5233
)

src/components/workspace/ReplInput.tsx

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,57 @@ export interface IReplInputProps {
1010
handleReplEval: () => void
1111
}
1212

13-
class ReplInput extends React.Component<IReplInputProps, {}> {
13+
class ReplInput extends React.PureComponent<IReplInputProps, {}> {
14+
private replInputBottom: HTMLDivElement
15+
16+
public componentDidUpdate() {
17+
if (this.replInputBottom.clientWidth >= window.innerWidth - 50) {
18+
/* There is a bug where
19+
* if the workspace has been resized via re-resizable such that the
20+
* has disappeared off the screen, width 63
21+
* then
22+
* calling scrollIntoView would cause the Repl to suddenly take up 100%
23+
* of the screen width. This pushes the editor off-screen so that the
24+
* user can no longer resize the workspace at all
25+
* Fix: the if condition is true when the Repl has dissapeared off-screen.
26+
* (-15 to account for the scrollbar */
27+
} else {
28+
this.replInputBottom.scrollIntoView()
29+
}
30+
}
31+
1432
public render() {
1533
return (
16-
<AceEditor
17-
className="repl-react-ace react-ace"
18-
mode="javascript"
19-
theme="cobalt"
20-
height="1px"
21-
width="100%"
22-
value={this.props.replValue}
23-
onChange={this.props.handleReplValueChange}
24-
commands={[
25-
{
26-
name: 'evaluate',
27-
bindKey: {
28-
win: 'Shift-Enter',
29-
mac: 'Shift-Enter'
30-
},
31-
exec: this.props.handleReplEval
32-
}
33-
]}
34-
minLines={1}
35-
maxLines={20}
36-
fontSize={14}
37-
highlightActiveLine={false}
38-
showGutter={false}
39-
/>
34+
<>
35+
<AceEditor
36+
className="repl-react-ace react-ace"
37+
mode="javascript"
38+
theme="cobalt"
39+
height="1px"
40+
width="100%"
41+
value={this.props.replValue}
42+
onChange={this.props.handleReplValueChange}
43+
commands={[
44+
{
45+
name: 'evaluate',
46+
bindKey: {
47+
win: 'Shift-Enter',
48+
mac: 'Shift-Enter'
49+
},
50+
exec: () => {
51+
this.replInputBottom.scrollIntoView()
52+
this.props.handleReplEval()
53+
}
54+
}
55+
]}
56+
minLines={1}
57+
maxLines={20}
58+
fontSize={14}
59+
highlightActiveLine={false}
60+
showGutter={false}
61+
/>
62+
<div className="replInputBottom" ref={e => (this.replInputBottom = e!)} />
63+
</>
4064
)
4165
}
4266
}

src/components/workspace/__tests__/__snapshots__/Editor.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`Editor renders correctly 1`] = `
44
"<HotKeys className=\\"Editor\\" handlers={{...}}>
55
<div className=\\"row editor-react-ace\\">
6-
<ReactAce className=\\"react-ace\\" mode=\\"javascript\\" theme=\\"cobalt\\" value=\\"\\" onChange={[Function: handleEditorValueChange]} height=\\"100%\\" commands={{...}} width=\\"100%\\" fontSize={14} highlightActiveLine={false} name=\\"brace-editor\\" focus={false} showGutter={true} onPaste={{...}} onLoad={{...}} onScroll={{...}} minLines={{...}} maxLines={{...}} readOnly={false} showPrintMargin={true} tabSize={4} cursorStart={1} editorProps={{...}} style={{...}} scrollMargin={{...}} setOptions={{...}} wrapEnabled={false} enableBasicAutocompletion={false} enableLiveAutocompletion={false} />
6+
<ReactAce className=\\"react-ace\\" commands={{...}} editorProps={{...}} fontSize={14} height=\\"100%\\" highlightActiveLine={false} mode=\\"javascript\\" onChange={[Function: handleEditorValueChange]} theme=\\"cobalt\\" value=\\"\\" width=\\"100%\\" name=\\"brace-editor\\" focus={false} showGutter={true} onPaste={{...}} onLoad={{...}} onScroll={{...}} minLines={{...}} maxLines={{...}} readOnly={false} showPrintMargin={true} tabSize={4} cursorStart={1} style={{...}} scrollMargin={{...}} setOptions={{...}} wrapEnabled={false} enableBasicAutocompletion={false} enableLiveAutocompletion={false} />
77
</div>
88
</HotKeys>"
99
`;

src/components/workspace/__tests__/__snapshots__/Repl.tsx.snap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ exports[`Repl renders correctly 1`] = `
4747
<HotKeys className=\\"repl-input-parent row pt-card pt-elevation-0\\" handlers={{...}}>
4848
<ReplInput output={{...}} replValue=\\"\\" handleReplValueChange={[Function: handleReplValueChange]} handleReplEval={[Function: handleReplEval]} handleReplOutputClear={[Function: handleReplOutputClear]} />
4949
</HotKeys>
50-
<div />
5150
</div>
5251
</div>"
5352
`;

src/components/workspace/side-content/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type SideContentTab = {
1313
body: JSX.Element
1414
}
1515

16-
class SideContent extends React.Component<SideContentProps, {}> {
16+
class SideContent extends React.PureComponent<SideContentProps, {}> {
1717
public render() {
1818
return (
1919
<div className="side-content">

0 commit comments

Comments
 (0)