Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
62e2c25
Update files and globals
remo5000 Jul 20, 2018
0a7cc7a
Add mockGlobals
remo5000 Jul 20, 2018
6fda3bd
Add action argument and reducer state update
remo5000 Jul 20, 2018
1b0c582
Add globals to state
remo5000 Jul 20, 2018
deb257c
Add globals side effect
remo5000 Jul 20, 2018
b368699
Make containers use globals argument
remo5000 Jul 20, 2018
be0c68a
Make components use globals
remo5000 Jul 20, 2018
021001c
Change update method for components (again)
remo5000 Jul 20, 2018
b6d9aec
Format files
remo5000 Jul 20, 2018
b7ece95
Update definition to match backend
remo5000 Jul 24, 2018
9a794ff
Change clearContext definition using external
remo5000 Jul 24, 2018
91cc1be
Simplify clearContext by using Library as arg
remo5000 Jul 24, 2018
0e9151d
Change handleClearContext arguments for components
remo5000 Jul 24, 2018
c87e3f6
Use handleClearContext in components
remo5000 Jul 24, 2018
f2dbc47
Update assessment test
remo5000 Jul 24, 2018
0a490b3
Use new clearContext in workspace containers
remo5000 Jul 24, 2018
e2223aa
Update ApplicationContainer
remo5000 Jul 24, 2018
1d79465
Update mock libraries
remo5000 Jul 24, 2018
fb2af03
Re-export ExternalLibraryName
remo5000 Jul 24, 2018
7263843
Update clearContext usage in sagas
remo5000 Jul 24, 2018
d9605f3
Fix reducer for CLEAR_CONTEXT
remo5000 Jul 24, 2018
3515fd1
Change handleClearContext arg for Application
remo5000 Jul 24, 2018
e460518
Change IWorkspaceState/externals->externalSymbols
remo5000 Jul 24, 2018
dc840c3
Type state.workspaces[location] instances in saga
remo5000 Jul 24, 2018
4fdb0dc
Fix externals references in saga
remo5000 Jul 24, 2018
e067e11
Remove inconsequential mentions of externals
remo5000 Jul 24, 2018
c245f01
Change externalLibrary -> externalLibraryName (PG)
remo5000 Jul 24, 2018
59ca55e
Rename some properties in Playground component
remo5000 Jul 24, 2018
1f8e4b3
Fix a reducer and some comments
remo5000 Jul 24, 2018
b617a09
Fix bug caused by changing IExternal props
remo5000 Jul 24, 2018
c5740f6
Format files
remo5000 Jul 24, 2018
870c62b
Add data transformations for Assessment
remo5000 Jul 24, 2018
b9f9c4e
Format files
remo5000 Jul 24, 2018
8fb1a7e
Fix rebase import order error
remo5000 Jul 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions src/actions/workspaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ActionCreator } from 'redux'

import { ExternalLibraryName } from '../components/assessment/assessmentShape'
import { Library } from '../components/assessment/assessmentShape'
import { IWorkspaceState } from '../reducers/states'
import * as actionTypes from './actionTypes'

Expand Down Expand Up @@ -86,30 +86,23 @@ export const playgroundExternalSelect: ActionCreator<actionTypes.IAction> = (
) => ({
type: actionTypes.PLAYGROUND_EXTERNAL_SELECT,
payload: {
external: external.displayName,
externalLibraryName: external.name,
workspaceLocation
}
})

/**
* Clears the js-slang Context at a specified workspace location.
*
* @param chapter the SICP chapter for the context to be set in
* @param externals a list of symbols to be exposed from the global scope
* @param externalLibraryName the name of the external library used
* @param library the Library that the context shall be using
* @param workspaceLocation the location of the workspace
*
* @see Library in assessmentShape.ts
*/
export const clearContext = (
chapter: number,
externals: string[],
externalLibraryName: ExternalLibraryName,
workspaceLocation: WorkspaceLocation
) => ({
export const clearContext = (library: Library, workspaceLocation: WorkspaceLocation) => ({
type: actionTypes.CLEAR_CONTEXT,
payload: {
chapter,
externals,
externalLibraryName,
library,
workspaceLocation
}
})
Expand Down
8 changes: 4 additions & 4 deletions src/components/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export interface IStateProps {
role?: Role
username?: string
currentPlaygroundChapter: number
currentPlaygroundExternals: string[]
currentPlaygroundExternalSymbols: string[]
}

export interface IDispatchProps {
handleClearContext: (chapter: number, externals: string[]) => void
handleClearContext: (chapter: number, symbols: string[]) => void
handleEditorValueChange: (val: string) => void
}

Expand Down Expand Up @@ -70,9 +70,9 @@ const parsePlayground = (props: IApplicationProps) => {
if (prgrm) {
props.handleEditorValueChange(prgrm)
}
/** Changes the chapter, retains the externals. */
/** Changes the chapter, retains the external symbols. */
if (lib) {
props.handleClearContext(lib, props.currentPlaygroundExternals)
props.handleClearContext(lib, props.currentPlaygroundExternalSymbols)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/components/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface IStateProps {
replValue: string
sideContentHeight?: number
sourceChapter: number
externalLibrary: string
externalLibraryName: string
}

export interface IDispatchProps {
Expand Down Expand Up @@ -58,7 +58,7 @@ class Playground extends React.Component<IPlaygroundProps, PlaygroundState> {
public render() {
const workspaceProps: WorkspaceProps = {
controlBarProps: {
externalLibrary: this.props.externalLibrary,
externalLibraryName: this.props.externalLibraryName,
handleChapterSelect: this.props.handleChapterSelect,
handleExternalSelect: this.props.handleExternalSelect,
handleEditorEval: this.props.handleEditorEval,
Expand Down
4 changes: 2 additions & 2 deletions src/components/__tests__/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ test('Application renders correctly', () => {
...mockRouterProps('/academy', {}),
title: 'Cadet',
currentPlaygroundChapter: 2,
currentPlaygroundExternals: [],
handleClearContext: (chapter: number, externals: string[]) => {},
currentPlaygroundExternalSymbols: [],
handleClearContext: (chapter: number, externalSymbols: string[]) => {},
handleEditorValueChange: (val: string) => {}
}
const app = <Application {...props} />
Expand Down
4 changes: 2 additions & 2 deletions src/components/__tests__/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { shallow } from 'enzyme'
import * as React from 'react'

import { mockRouterProps } from '../../mocks/components'
import { ExternalLibraryNames } from '../assessment/assessmentShape'
import Playground, { IPlaygroundProps } from '../Playground'

const baseProps = {
Expand All @@ -11,8 +12,7 @@ const baseProps = {
editorWidth: '50%',
sideContentHeight: 40,
sourceChapter: 2,
/** TODO use constant value */
externalLibrary: 'none',
externalLibraryName: ExternalLibraryNames.NONE,
output: [],
replValue: '',
handleBrowseHistoryDown: () => {},
Expand Down
24 changes: 7 additions & 17 deletions src/components/academy/grading/GradingWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { NonIdealState, Spinner, Text } from '@blueprintjs/core'
import { IconNames } from '@blueprintjs/icons'
import * as React from 'react'

import { ExternalLibraryName } from '../../../components/assessment/assessmentShape'
import GradingEditor from '../../../containers/academy/grading/GradingEditorContainer'
import { InterpreterOutput, IWorkspaceState } from '../../../reducers/states'
import { history } from '../../../utils/history'
import {
IMCQQuestion,
IProgrammingQuestion,
IQuestion,
Library,
QuestionTypes
} from '../../assessment/assessmentShape'
import Workspace, { WorkspaceProps } from '../../workspace'
Expand Down Expand Up @@ -42,11 +42,7 @@ export type DispatchProps = {
handleBrowseHistoryUp: () => void
handleChangeActiveTab: (activeTab: number) => void
handleChapterSelect: (chapter: any, changeEvent: any) => void
handleClearContext: (
chapter: number,
externals: string[],
externalLibraryName: ExternalLibraryName
) => void
handleClearContext: (library: Library) => void
handleEditorEval: () => void
handleEditorValueChange: (val: string) => void
handleEditorWidthChange: (widthChange: number) => void
Expand All @@ -62,19 +58,16 @@ export type DispatchProps = {

class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
/**
* First, check for a need to reset the workspace,
* then fetch the grading. This works because a change in
* submissionId or questionId results in a navigation, causing
* this component to be mounted again. The handleGradingFetch
* occurs after the call to checkWorkspaceReset finishes.
* After mounting (either an older copy of the grading
* or a loading screen), try to fetch a newer grading.
*/
public componentDidMount() {
this.props.handleGradingFetch(this.props.submissionId)
}

/**
* After the Grading is fetched, there is a check for wether the
* workspace needs to be udpated (a change in submissionId or questionId)
* Once there is an update (due to the grading being fetched), check
* if a workspace reset is needed.
*/
public componentDidUpdate() {
this.checkWorkspaceReset(this.props)
Expand Down Expand Up @@ -158,9 +151,6 @@ class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
this.props.storedQuestionId !== questionId
) {
const question = this.props.grading[questionId].question as IQuestion
const chapter = question.library.chapter
const externalName = question.library.externalLibraryName
const externals = question.library.externals
const editorValue =
question.type === QuestionTypes.programming
? question.answer !== null
Expand All @@ -169,7 +159,7 @@ class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
: null
this.props.handleUpdateCurrentSubmissionId(submissionId, questionId)
this.props.handleResetWorkspace({ editorValue })
this.props.handleClearContext(chapter, externals, externalName)
this.props.handleClearContext(question.library)
}
}

Expand Down
25 changes: 10 additions & 15 deletions src/components/assessment/AssessmentWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import Workspace, { WorkspaceProps } from '../workspace'
import { ControlBarProps } from '../workspace/ControlBar'
import { SideContentProps } from '../workspace/side-content'
import {
ExternalLibraryName,
IAssessment,
IMCQQuestion,
IProgrammingQuestion,
IQuestion,
Library,
QuestionTypes
} from './assessmentShape'

Expand Down Expand Up @@ -45,11 +45,7 @@ export type DispatchProps = {
handleBrowseHistoryUp: () => void
handleChangeActiveTab: (activeTab: number) => void
handleChapterSelect: (chapter: any, changeEvent: any) => void
handleClearContext: (
chapter: number,
externals: string[],
externalLibraryName: ExternalLibraryName
) => void
handleClearContext: (library: Library) => void
handleEditorEval: () => void
handleEditorValueChange: (val: string) => void
handleEditorWidthChange: (widthChange: number) => void
Expand All @@ -70,11 +66,9 @@ class AssessmentWorkspace extends React.Component<
public state = { showOverlay: false }

/**
* First, check for a need to reset the workspace,
* then fetch the assessment. This works because a change in
* assessmentId or questionId results in a navigation, causing
* this component to be mounted again. The handleAssessmentFetch
* occurs after the call to checkWorkspaceReset finishes.
* After mounting (either an older copy of the assessment
* or a loading screen), try to fetch a newer assessment,
* and show the briefing.
*/
public componentDidMount() {
this.props.handleAssessmentFetch(this.props.assessmentId)
Expand All @@ -83,6 +77,10 @@ class AssessmentWorkspace extends React.Component<
}
}

/**
* Once there is an update (due to the assessment being fetched), check
* if a workspace reset is needed.
*/
public componentDidUpdate() {
this.checkWorkspaceReset(this.props)
}
Expand Down Expand Up @@ -178,9 +176,6 @@ class AssessmentWorkspace extends React.Component<
this.props.storedQuestionId !== questionId
) {
const question = this.props.assessment.questions[questionId]
const chapter = question.library.chapter
const externalName = question.library.externalLibraryName
const externals = question.library.externals
const editorValue =
question.type === QuestionTypes.programming
? question.answer !== null
Expand All @@ -189,7 +184,7 @@ class AssessmentWorkspace extends React.Component<
: null
this.props.handleUpdateCurrentAssessmentId(assessmentId, questionId)
this.props.handleResetWorkspace({ editorValue })
this.props.handleClearContext(chapter, externals, externalName)
this.props.handleClearContext(question.library)
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/assessment/__tests__/AssessmentWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { shallow } from 'enzyme'
import * as React from 'react'

import { mockAssessments } from '../../../mocks/assessmentAPI'
import { Library } from '../assessmentShape'
import AssessmentWorkspace, { AssessmentWorkspaceProps } from '../AssessmentWorkspace'

const defaultProps: AssessmentWorkspaceProps = {
Expand All @@ -15,7 +16,7 @@ const defaultProps: AssessmentWorkspaceProps = {
handleBrowseHistoryUp: () => {},
handleChangeActiveTab: (activeTab: number) => {},
handleChapterSelect: (chapter: any, changeEvent: any) => {},
handleClearContext: (chapter: number, externals: string[]) => {},
handleClearContext: (library: Library) => {},
handleEditorEval: () => {},
handleEditorValueChange: (val: string) => {},
handleEditorWidthChange: (widthChange: number) => {},
Expand Down
11 changes: 7 additions & 4 deletions src/components/assessment/assessmentShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,13 @@ export enum ExternalLibraryNames {

export type ExternalLibraryName = keyof typeof ExternalLibraryNames

type ExternalLibrary = {
name: ExternalLibraryName
symbols: string[]
}

export type Library = {
chapter: number
externalLibraryName: ExternalLibraryName
files: string[]
externals: string[]
globals: string[]
external: ExternalLibrary
globals: Array<[string, any]>
}
22 changes: 11 additions & 11 deletions src/components/workspace/ControlBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type ControlBarProps = {
isRunning: boolean
queryString?: string
sourceChapter: number
externalLibrary?: string
externalLibraryName?: string
handleChapterSelect?: (i: IChapter, e: React.ChangeEvent<HTMLSelectElement>) => void
handleExternalSelect?: (i: IExternal, e: React.ChangeEvent<HTMLSelectElement>) => void
handleEditorEval: () => void
Expand All @@ -44,8 +44,8 @@ interface IChapter {
*/
interface IExternal {
key: number
displayName: string
externals: string[]
name: string
symbols: string[]
}

class ControlBar extends React.PureComponent<ControlBarProps, {}> {
Expand Down Expand Up @@ -120,8 +120,8 @@ class ControlBar extends React.PureComponent<ControlBarProps, {}> {
? chapterSelect(this.props.sourceChapter, this.props.handleChapterSelect)
: undefined
const externalSelectButton =
this.props.hasChapterSelect && this.props.externalLibrary !== undefined
? externalSelect(this.props.externalLibrary, this.props.handleExternalSelect)
this.props.hasChapterSelect && this.props.externalLibraryName !== undefined
? externalSelect(this.props.externalLibraryName, this.props.handleExternalSelect!)
: undefined
return (
<div className="ControlBar_editor pt-button-group">
Expand Down Expand Up @@ -202,19 +202,19 @@ const chapterRenderer: ItemRenderer<IChapter> = (chap, { handleClick, modifiers,
<MenuItem active={false} key={chap.chapter} onClick={handleClick} text={chap.displayName} />
)

const externals = Array.from(externalLibraries.entries()).map((entry, index) => ({
displayName: entry[0],
const iExternals = Array.from(externalLibraries.entries()).map((entry, index) => ({
name: entry[0],
key: index,
externals: entry[1]
symbols: entry[1]
}))

const externalSelect = (
currentExternal: string,
handleSelect = (i: IExternal, e: React.ChangeEvent<HTMLSelectElement>) => {}
handleSelect: (i: IExternal, e: React.ChangeEvent<HTMLSelectElement>) => void
) => (
<ExternalSelectComponent
className="pt-minimal"
items={externals}
items={iExternals}
onItemSelect={handleSelect}
itemRenderer={externalRenderer}
filterable={false}
Expand All @@ -226,7 +226,7 @@ const externalSelect = (
const ExternalSelectComponent = Select.ofType<IExternal>()

const externalRenderer: ItemRenderer<IExternal> = (external, { handleClick, modifiers, query }) => (
<MenuItem active={false} key={external.key} onClick={handleClick} text={external.displayName} />
<MenuItem active={false} key={external.key} onClick={handleClick} text={external.name} />
)

export default ControlBar
20 changes: 17 additions & 3 deletions src/containers/ApplicationContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,30 @@ const mapStateToProps: MapStateToProps<IStateProps, {}, IState> = state => ({
role: state.session.role,
username: state.session.username,
currentPlaygroundChapter: state.workspaces.playground.context.chapter,
currentPlaygroundExternals: state.workspaces.playground.externals
currentPlaygroundExternalSymbols: state.workspaces.playground.externalSymbols
})

const workspaceLocation = WorkspaceLocations.playground

const mapDispatchToProps: MapDispatchToProps<IDispatchProps, {}> = (dispatch: Dispatch<any>) =>
bindActionCreators(
{
handleClearContext: (chapter: number, externals: string[]) =>
clearContext(chapter, externals, ExternalLibraryNames.NONE, workspaceLocation),
/**
* Note that an empty globals is passed (as this is never used in URLs)
* and that ExternalLibraryNames.NONE is used (as URL library support is not ready yet).
*/
handleClearContext: (chapter: number, symbols: string[]) =>
clearContext(
{
chapter,
external: {
name: ExternalLibraryNames.NONE,
symbols
},
globals: []
},
workspaceLocation
),
handleEditorValueChange: (val: string) => updateEditorValue(val, workspaceLocation)
},
dispatch
Expand Down
Loading