From 3080478b508ee29a55276c672148206c7160b823 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Fri, 13 Jul 2018 16:54:14 +0800 Subject: [PATCH 01/27] Add sound externals for playground --- src/reducers/states.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/reducers/states.ts b/src/reducers/states.ts index 611f6b030e..3f94348c8d 100644 --- a/src/reducers/states.ts +++ b/src/reducers/states.ts @@ -132,7 +132,26 @@ const latestSourceChapter = sourceChapters.slice(-1)[0] * TODO use constants * TODO move this to a file closer to the libraries */ -const libEntries: Array<[string, string[]]> = [['none', []], ['sound', ['make_sourcesound']]] +const libEntries: Array<[string, string[]]> = [ + ['none', []], + [ + 'sound', + [ + 'make_sourcesound', + 'get_wave', + 'get_duration', + 'is_sound', + 'play', + 'stop', + 'cut_sourcesound', + 'cut', + 'sourcesound_to_sound', + 'autocut_sourcesound', + 'consecutively', + 'simultaneously' + ] + ] +] export const externalLibraries: Map = new Map(libEntries) const currentEnvironment = (): ApplicationEnvironment => { From 3e16037881941326d2adcf7650a2c283ba433f2c Mon Sep 17 00:00:00 2001 From: remo5000 Date: Fri, 13 Jul 2018 17:23:17 +0800 Subject: [PATCH 02/27] Simplify definitions - createDefaultWorkspace has only 1 argument (leave the library and chapter setting to CLEAR_CONTEXT) - IWorkspaceState contains externals --- src/reducers/states.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/reducers/states.ts b/src/reducers/states.ts index 3f94348c8d..0ebe313fab 100644 --- a/src/reducers/states.ts +++ b/src/reducers/states.ts @@ -49,6 +49,7 @@ interface IWorkspaceState { readonly replValue: string readonly sideContentActiveTab: number readonly sideContentHeight?: number + readonly externals: string[] } export interface ISessionState { @@ -183,20 +184,15 @@ export const defaultEditorValue = '// Type your program in here!' * Takes in parameters to set the js-slang library and chapter. * * @param location the location of the workspace, used for context - * @param chapter the chapter number for the js-slang interpreter - * @param externals any external library exposed symbols */ -export const createDefaultWorkspace = ( - location: WorkspaceLocation, - chapter: number = latestSourceChapter, - externals?: string[] -): IWorkspaceState => ({ - context: createContext(chapter, externals, location), +export const createDefaultWorkspace = (location: WorkspaceLocation): IWorkspaceState => ({ + context: createContext(latestSourceChapter, undefined, location), editorValue: defaultEditorValue, editorWidth: '50%', output: [], replValue: '', - sideContentActiveTab: 0 + sideContentActiveTab: 0, + externals: [] }) export const defaultComments = 'Comments **here**. Use `markdown` if you ~~are cool~~ want!' From d87a9238975d7ce938a0c59259db67836ac7dd2f Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 11:11:08 +0800 Subject: [PATCH 03/27] Change resetAssessmentWorkspace reducer --- src/actions/workspaces.ts | 8 ++------ src/components/assessment/AssessmentWorkspace.tsx | 4 ++-- src/reducers/workspaces.ts | 4 +--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index 0dcc57834b..39c66147d4 100644 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -134,12 +134,8 @@ export const sendReplInputToOutput: ActionCreator = ( } }) -export const resetAssessmentWorkspace = (chapter: number, externals: string[]) => ({ - type: actionTypes.RESET_ASSESSMENT_WORKSPACE, - payload: { - chapter, - externals - } +export const resetAssessmentWorkspace = () => ({ + type: actionTypes.RESET_ASSESSMENT_WORKSPACE }) export const updateCurrentAssessmentId = (assessmentId: number, questionId: number) => ({ diff --git a/src/components/assessment/AssessmentWorkspace.tsx b/src/components/assessment/AssessmentWorkspace.tsx index 80d9454b39..4952538b20 100644 --- a/src/components/assessment/AssessmentWorkspace.tsx +++ b/src/components/assessment/AssessmentWorkspace.tsx @@ -1,5 +1,4 @@ -import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' -import { IconNames } from '@blueprintjs/icons' +import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' import { IconNames } from '@blueprintjs/icons' import * as React from 'react' import { InterpreterOutput } from '../../reducers/states' @@ -159,6 +158,7 @@ class AssessmentWorkspace extends React.Component< const chapter = this.props.assessment.questions[questionId].library.chapter const externals = this.props.assessment.questions[questionId].library.externals this.props.handleUpdateCurrentAssessmentId(assessmentId, questionId) + // TODO clear context here using chapter and externals this.props.handleResetAssessmentWorkspace(chapter, externals) } } diff --git a/src/reducers/workspaces.ts b/src/reducers/workspaces.ts index 5662d3fe31..14c010cee0 100644 --- a/src/reducers/workspaces.ts +++ b/src/reducers/workspaces.ts @@ -259,11 +259,9 @@ export const reducer: Reducer = ( * Resets the assessment workspace (under state.workspaces.assessment). */ case RESET_ASSESSMENT_WORKSPACE: - chapter = action.payload.chapter - externals = action.payload.externals return { ...state, - assessment: createDefaultWorkspace(WorkspaceLocations.assessment, chapter, externals), + assessment: createDefaultWorkspace(WorkspaceLocations.assessment), gradingCommentsValue: defaultComments, gradingXP: undefined } From 107ce38dcde5489bc54c0b9c5fa35d7cc692a0b5 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 11:50:23 +0800 Subject: [PATCH 04/27] Use clearContext chapter/externals args in comps I.e in both components and containers --- src/components/assessment/AssessmentWorkspace.tsx | 12 +++++++----- .../assessment/__tests__/AssessmentWorkspace.tsx | 4 ++-- .../assessment/AssessmentWorkspaceContainer.ts | 7 ++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/assessment/AssessmentWorkspace.tsx b/src/components/assessment/AssessmentWorkspace.tsx index 4952538b20..1bae74e409 100644 --- a/src/components/assessment/AssessmentWorkspace.tsx +++ b/src/components/assessment/AssessmentWorkspace.tsx @@ -1,4 +1,5 @@ -import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' import { IconNames } from '@blueprintjs/icons' +import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' +import { IconNames } from '@blueprintjs/icons' import * as React from 'react' import { InterpreterOutput } from '../../reducers/states' @@ -13,7 +14,7 @@ import { IMCQQuestion, IProgrammingQuestion, IQuestion, - QuestionTypes + QuestionTypes, } from './assessmentShape' export type AssessmentWorkspaceProps = DispatchProps & OwnProps & StateProps @@ -41,6 +42,7 @@ export type DispatchProps = { handleAssessmentFetch: (assessmentId: number) => void handleChangeActiveTab: (activeTab: number) => void handleChapterSelect: (chapter: any, changeEvent: any) => void + handleClearContext: (chapter: number, externals: string[]) => void handleEditorEval: () => void handleEditorValueChange: (val: string) => void handleEditorWidthChange: (widthChange: number) => void @@ -48,7 +50,7 @@ export type DispatchProps = { handleReplEval: () => void handleReplOutputClear: () => void handleReplValueChange: (newValue: string) => void - handleResetAssessmentWorkspace: (chapter: number, externals: string[]) => void + handleResetAssessmentWorkspace: () => void handleSideContentHeightChange: (heightChange: number) => void handleUpdateCurrentAssessmentId: (assessmentId: number, questionId: number) => void } @@ -158,8 +160,8 @@ class AssessmentWorkspace extends React.Component< const chapter = this.props.assessment.questions[questionId].library.chapter const externals = this.props.assessment.questions[questionId].library.externals this.props.handleUpdateCurrentAssessmentId(assessmentId, questionId) - // TODO clear context here using chapter and externals - this.props.handleResetAssessmentWorkspace(chapter, externals) + this.props.handleResetAssessmentWorkspace() + this.props.handleClearContext(chapter, externals) } } diff --git a/src/components/assessment/__tests__/AssessmentWorkspace.tsx b/src/components/assessment/__tests__/AssessmentWorkspace.tsx index 8626b44e11..17cb40ba95 100644 --- a/src/components/assessment/__tests__/AssessmentWorkspace.tsx +++ b/src/components/assessment/__tests__/AssessmentWorkspace.tsx @@ -12,6 +12,7 @@ const defaultProps: AssessmentWorkspaceProps = { handleAssessmentFetch: (assessmentId: number) => {}, handleChangeActiveTab: (activeTab: number) => {}, handleChapterSelect: (chapter: any, changeEvent: any) => {}, + handleClearContext: (chapter: number, externals: string[]) => {}, handleEditorEval: () => {}, handleEditorValueChange: (val: string) => {}, handleEditorWidthChange: (widthChange: number) => {}, @@ -22,8 +23,7 @@ const defaultProps: AssessmentWorkspaceProps = { handleResetAssessmentWorkspace: () => {}, handleSideContentHeightChange: (heightChange: number) => {}, handleUpdateCurrentAssessmentId: (a: number, q: number) => {}, - isRunning: false, - output: [], + isRunning: false, output: [], questionId: 0, replValue: '' } diff --git a/src/containers/assessment/AssessmentWorkspaceContainer.ts b/src/containers/assessment/AssessmentWorkspaceContainer.ts index 93d4407482..f9568498f9 100644 --- a/src/containers/assessment/AssessmentWorkspaceContainer.ts +++ b/src/containers/assessment/AssessmentWorkspaceContainer.ts @@ -7,15 +7,15 @@ import { changeEditorWidth, changeSideContentHeight, chapterSelect, + clearContext, clearReplOutput, evalEditor, evalRepl, fetchAssessment, updateEditorValue, updateReplValue, - WorkspaceLocation } from '../../actions' -import { resetAssessmentWorkspace, updateCurrentAssessmentId } from '../../actions/workspaces' +import { resetAssessmentWorkspace, WorkspaceLocation, updateCurrentAssessmentId } from '../../actions/workspaces' import AssessmentWorkspace, { DispatchProps, OwnProps, @@ -47,6 +47,7 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis handleChangeActiveTab: (activeTab: number) => changeActiveTab(activeTab, location), handleChapterSelect: (chapter: any, changeEvent: any) => chapterSelect(chapter, changeEvent, location), + handleClearContext: (chapter: number, externals: string[]) => clearContext(location, chapter, externals), handleEditorEval: () => evalEditor(location), handleEditorValueChange: (val: string) => updateEditorValue(val, location), handleEditorWidthChange: (widthChange: number) => changeEditorWidth(widthChange, location), @@ -54,7 +55,7 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis handleReplEval: () => evalRepl(location), handleReplOutputClear: () => clearReplOutput(location), handleReplValueChange: (newValue: string) => updateReplValue(newValue, location), - handleResetAssessmentWorkspace: resetAssessmentWorkspace, + handleResetAssessmentWorkspace: () => resetAssessmentWorkspace, handleSideContentHeightChange: (heightChange: number) => changeSideContentHeight(heightChange, location), handleUpdateCurrentAssessmentId: updateCurrentAssessmentId From c97d8d771343c191523885c39d9d66a83aafca32 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 11:52:04 +0800 Subject: [PATCH 05/27] Update arguments for action creator --- src/actions/workspaces.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index 39c66147d4..5f53d638de 100644 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -81,9 +81,13 @@ export const librarySelect: ActionCreator = ( } }) -export const clearContext = (workspaceLocation: WorkspaceLocation) => ({ +export const clearContext = (workspaceLocation: WorkspaceLocation, chapter: number, externals: string[]) => ({ type: actionTypes.CLEAR_CONTEXT, - payload: { workspaceLocation } + payload: { + workspaceLocation, + chapter, + externals + } }) export const clearReplInput = (workspaceLocation: WorkspaceLocation) => ({ From bd7503d22b09b21e8f855b910caa35b1a7c12fa6 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 11:56:28 +0800 Subject: [PATCH 06/27] Use clearContext with 3 args in saga --- src/sagas/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sagas/index.ts b/src/sagas/index.ts index ca2ec9edbf..cf396ab4e3 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -65,8 +65,12 @@ function* workspaceSaga(): SagaIterator { yield takeEvery(actionTypes.EVAL_EDITOR, function*(action) { const location = (action as actionTypes.IAction).payload.workspaceLocation const code: string = yield select((state: IState) => state.workspaces[location].editorValue) + const chapter: number = yield select((state: IState) => state.workspaces[location].context.chapter) + const externals: string[] = yield select((state: IState) => state.workspaces[location].externals) + /** End any code that is running right now. */ yield put(actions.beginInterruptExecution(location)) - yield put(actions.clearContext(location)) + /** Clear the context, with the same chapter and externals as before. */ + yield put(actions.clearContext(location, chapter, externals)) yield put(actions.clearReplOutput(location)) context = yield select((state: IState) => state.workspaces[location].context) yield* evalCode(code, context, location) From cc25f8f7d2ac4eab0462a7f92127a0d4398f779f Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 11:56:58 +0800 Subject: [PATCH 07/27] Format files and fix import order --- src/actions/workspaces.ts | 8 ++++++-- src/components/assessment/AssessmentWorkspace.tsx | 4 ++-- .../assessment/__tests__/AssessmentWorkspace.tsx | 3 ++- .../assessment/AssessmentWorkspaceContainer.ts | 11 ++++++++--- src/sagas/index.ts | 8 ++++++-- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index 5f53d638de..d87f52fb80 100644 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -81,9 +81,13 @@ export const librarySelect: ActionCreator = ( } }) -export const clearContext = (workspaceLocation: WorkspaceLocation, chapter: number, externals: string[]) => ({ +export const clearContext = ( + workspaceLocation: WorkspaceLocation, + chapter: number, + externals: string[] +) => ({ type: actionTypes.CLEAR_CONTEXT, - payload: { + payload: { workspaceLocation, chapter, externals diff --git a/src/components/assessment/AssessmentWorkspace.tsx b/src/components/assessment/AssessmentWorkspace.tsx index 1bae74e409..0df905e15b 100644 --- a/src/components/assessment/AssessmentWorkspace.tsx +++ b/src/components/assessment/AssessmentWorkspace.tsx @@ -1,4 +1,4 @@ -import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' +import { Button, Card, Dialog, NonIdealState, Spinner, Text } from '@blueprintjs/core' import { IconNames } from '@blueprintjs/icons' import * as React from 'react' @@ -14,7 +14,7 @@ import { IMCQQuestion, IProgrammingQuestion, IQuestion, - QuestionTypes, + QuestionTypes } from './assessmentShape' export type AssessmentWorkspaceProps = DispatchProps & OwnProps & StateProps diff --git a/src/components/assessment/__tests__/AssessmentWorkspace.tsx b/src/components/assessment/__tests__/AssessmentWorkspace.tsx index 17cb40ba95..ec29808140 100644 --- a/src/components/assessment/__tests__/AssessmentWorkspace.tsx +++ b/src/components/assessment/__tests__/AssessmentWorkspace.tsx @@ -23,7 +23,8 @@ const defaultProps: AssessmentWorkspaceProps = { handleResetAssessmentWorkspace: () => {}, handleSideContentHeightChange: (heightChange: number) => {}, handleUpdateCurrentAssessmentId: (a: number, q: number) => {}, - isRunning: false, output: [], + isRunning: false, + output: [], questionId: 0, replValue: '' } diff --git a/src/containers/assessment/AssessmentWorkspaceContainer.ts b/src/containers/assessment/AssessmentWorkspaceContainer.ts index f9568498f9..c2fd803cce 100644 --- a/src/containers/assessment/AssessmentWorkspaceContainer.ts +++ b/src/containers/assessment/AssessmentWorkspaceContainer.ts @@ -13,9 +13,13 @@ import { evalRepl, fetchAssessment, updateEditorValue, - updateReplValue, + updateReplValue } from '../../actions' -import { resetAssessmentWorkspace, WorkspaceLocation, updateCurrentAssessmentId } from '../../actions/workspaces' +import { + resetAssessmentWorkspace, + updateCurrentAssessmentId, + WorkspaceLocation +} from '../../actions/workspaces' import AssessmentWorkspace, { DispatchProps, OwnProps, @@ -47,7 +51,8 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis handleChangeActiveTab: (activeTab: number) => changeActiveTab(activeTab, location), handleChapterSelect: (chapter: any, changeEvent: any) => chapterSelect(chapter, changeEvent, location), - handleClearContext: (chapter: number, externals: string[]) => clearContext(location, chapter, externals), + handleClearContext: (chapter: number, externals: string[]) => + clearContext(location, chapter, externals), handleEditorEval: () => evalEditor(location), handleEditorValueChange: (val: string) => updateEditorValue(val, location), handleEditorWidthChange: (widthChange: number) => changeEditorWidth(widthChange, location), diff --git a/src/sagas/index.ts b/src/sagas/index.ts index cf396ab4e3..502bc19f31 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -65,8 +65,12 @@ function* workspaceSaga(): SagaIterator { yield takeEvery(actionTypes.EVAL_EDITOR, function*(action) { const location = (action as actionTypes.IAction).payload.workspaceLocation const code: string = yield select((state: IState) => state.workspaces[location].editorValue) - const chapter: number = yield select((state: IState) => state.workspaces[location].context.chapter) - const externals: string[] = yield select((state: IState) => state.workspaces[location].externals) + const chapter: number = yield select( + (state: IState) => state.workspaces[location].context.chapter + ) + const externals: string[] = yield select( + (state: IState) => state.workspaces[location].externals + ) /** End any code that is running right now. */ yield put(actions.beginInterruptExecution(location)) /** Clear the context, with the same chapter and externals as before. */ From e2bbe93a5a42780a2b13e87b86d90ccff9314ce2 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 12:46:07 +0800 Subject: [PATCH 08/27] Change prop definitions for Application To include clearContext instead of changeChapter, and To utilise implementing an IStateProps --- src/components/Application.tsx | 8 ++++++-- src/components/__tests__/Application.tsx | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/Application.tsx b/src/components/Application.tsx index 4178061b48..f80586aadc 100644 --- a/src/components/Application.tsx +++ b/src/components/Application.tsx @@ -11,15 +11,19 @@ import { Role, sourceChapters } from '../reducers/states' import NavigationBar from './NavigationBar' import NotFound from './NotFound' -export interface IApplicationProps extends IDispatchProps, RouteComponentProps<{}> { +export interface IApplicationProps extends IDispatchProps, IStateProps, RouteComponentProps<{}> {} + +export interface IStateProps { title: string accessToken?: string role?: Role username?: string + currentChapter: number + currentExternals: string[] } export interface IDispatchProps { - handleChangeChapter: (chapter: number) => void + handleClearContext: (chapter: number, externals: string[]) => void handleEditorValueChange: (val: string) => void } diff --git a/src/components/__tests__/Application.tsx b/src/components/__tests__/Application.tsx index 3344f41323..cf8d56e191 100644 --- a/src/components/__tests__/Application.tsx +++ b/src/components/__tests__/Application.tsx @@ -8,7 +8,9 @@ test('Application renders correctly', () => { const props: IApplicationProps = { ...mockRouterProps('/academy', {}), title: 'Cadet', - handleChangeChapter: (chp: any) => {}, + currentChapter: 2, + currentExternals: [], + handleClearContext: (chapter: number, externals: string[]) => {}, handleEditorValueChange: (val: string) => {} } const app = From 1b72a13a800cdd6f1eb0a8c99230fa715bd5c8bd Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 12:49:44 +0800 Subject: [PATCH 09/27] Rename props to be more specific --- src/components/Application.tsx | 4 ++-- src/components/__tests__/Application.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Application.tsx b/src/components/Application.tsx index f80586aadc..d4c8d31878 100644 --- a/src/components/Application.tsx +++ b/src/components/Application.tsx @@ -18,8 +18,8 @@ export interface IStateProps { accessToken?: string role?: Role username?: string - currentChapter: number - currentExternals: string[] + currentPlaygroundChapter: number + currentPlaygroundExternals: string[] } export interface IDispatchProps { diff --git a/src/components/__tests__/Application.tsx b/src/components/__tests__/Application.tsx index cf8d56e191..74f5248db0 100644 --- a/src/components/__tests__/Application.tsx +++ b/src/components/__tests__/Application.tsx @@ -8,8 +8,8 @@ test('Application renders correctly', () => { const props: IApplicationProps = { ...mockRouterProps('/academy', {}), title: 'Cadet', - currentChapter: 2, - currentExternals: [], + currentPlaygroundChapter: 2, + currentPlaygroundExternals: [], handleClearContext: (chapter: number, externals: string[]) => {}, handleEditorValueChange: (val: string) => {} } From 1074ef5163e487aebeb9e906a125192d31207dc1 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 12:50:11 +0800 Subject: [PATCH 10/27] Update props for Application container --- src/containers/ApplicationContainer.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/containers/ApplicationContainer.ts b/src/containers/ApplicationContainer.ts index 15a874d8a9..8121e4079b 100644 --- a/src/containers/ApplicationContainer.ts +++ b/src/containers/ApplicationContainer.ts @@ -2,8 +2,9 @@ import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux' import { withRouter } from 'react-router' import { bindActionCreators, Dispatch } from 'redux' -import { changeChapter, updateEditorValue } from '../actions' -import Application, { IDispatchProps } from '../components/Application' +import { clearContext, updateEditorValue } from '../actions' +import { WorkspaceLocations } from '../actions/workspaces' +import Application, { IDispatchProps, IStateProps } from '../components/Application' import { IState } from '../reducers/states' /** @@ -13,18 +14,23 @@ import { IState } from '../reducers/states' * as the routing properties of @type {RouteComponentProps} are * provided using the withRouter() method below. */ -const mapStateToProps: MapStateToProps<{ title: string }, {}, IState> = state => ({ +const mapStateToProps: MapStateToProps = state => ({ title: state.application.title, accessToken: state.session.accessToken, role: state.session.role, - username: state.session.username + username: state.session.username, + currentPlaygroundChapter: state.workspaces.playground.context.chapter, + currentPlaygroundExternals: state.workspaces.playground.externals }) +const workspaceLocation = WorkspaceLocations.playground + const mapDispatchToProps: MapDispatchToProps = (dispatch: Dispatch) => bindActionCreators( { - handleChangeChapter: (chapter: number) => changeChapter(chapter, 'playground'), - handleEditorValueChange: (val: string) => updateEditorValue(val, 'playground') + handleClearContext: (chapter: number, externals: string[]) => + clearContext(workspaceLocation, chapter, externals), + handleEditorValueChange: (val: string) => updateEditorValue(val, workspaceLocation) }, dispatch ) From dfab518b0d74c435ffb4d8b2ae5308529492092f Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 12:50:26 +0800 Subject: [PATCH 11/27] Use clearContext for saga chapter selection --- src/sagas/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sagas/index.ts b/src/sagas/index.ts index 502bc19f31..ac9ae09286 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -94,8 +94,11 @@ function* workspaceSaga(): SagaIterator { const location = (action as actionTypes.IAction).payload.workspaceLocation const newChapter = (action as actionTypes.IAction).payload.chapter const oldChapter = yield select((state: IState) => state.workspaces[location].context.chapter) + const externals: string[] = yield select( + (state: IState) => state.workspaces[location].externals + ) if (newChapter !== oldChapter) { - yield put(actions.changeChapter(newChapter, location)) + yield put(actions.clearContext(location, newChapter, externals)) yield put(actions.clearReplOutput(location)) yield call(showSuccessMessage, `Switched to Source \xa7${newChapter}`) } From 3d527dbdce5a8dab9b4e91cdfea66708ac5f7d0f Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 12:52:18 +0800 Subject: [PATCH 12/27] Use handleClearContext in Application component --- src/components/Application.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Application.tsx b/src/components/Application.tsx index d4c8d31878..3188549023 100644 --- a/src/components/Application.tsx +++ b/src/components/Application.tsx @@ -70,8 +70,9 @@ const parsePlayground = (props: IApplicationProps) => { if (prgrm) { props.handleEditorValueChange(prgrm) } + /** Changes the chapter, retains the externals. */ if (lib) { - props.handleChangeChapter(lib) + props.handleClearContext(lib, props.currentPlaygroundExternals) } } From daf317b23c81d51d9f5487e73a6653962ef56dc8 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 13:00:50 +0800 Subject: [PATCH 13/27] Change props for GradingWorkspace --- src/components/academy/grading/GradingWorkspace.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/academy/grading/GradingWorkspace.tsx b/src/components/academy/grading/GradingWorkspace.tsx index 2cda665d4e..d4c99529f3 100644 --- a/src/components/academy/grading/GradingWorkspace.tsx +++ b/src/components/academy/grading/GradingWorkspace.tsx @@ -40,6 +40,7 @@ export type DispatchProps = { handleGradingFetch: (submissionId: number) => void handleChangeActiveTab: (activeTab: number) => void handleChapterSelect: (chapter: any, changeEvent: any) => void + handleClearContext: (chapter: number, externals: string[]) => void handleEditorEval: () => void handleEditorValueChange: (val: string) => void handleEditorWidthChange: (widthChange: number) => void @@ -47,8 +48,7 @@ export type DispatchProps = { handleReplEval: () => void handleReplOutputClear: () => void handleReplValueChange: (newValue: string) => void - /** Resetting the Assessment Workspace as this is the part of state Grading uses. */ - handleResetAssessmentWorkspace: (chapter: number, externals: string[]) => void + handleResetAssessmentWorkspace: () => void handleSideContentHeightChange: (heightChange: number) => void handleUpdateCurrentSubmissionId: (submissionId: number, questionId: number) => void } @@ -137,7 +137,8 @@ class GradingWorkspace extends React.Component { const chapter = this.props.grading[questionId].question.library.chapter const externals = this.props.grading[questionId].question.library.externals this.props.handleUpdateCurrentSubmissionId(submissionId, questionId) - this.props.handleResetAssessmentWorkspace(chapter, externals) + this.props.handleResetAssessmentWorkspace() + this.props.handleClearContext(chapter, externals) } } From 1e180a6d5d79425549cc8620122ff0e5f3f6f809 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 13:17:37 +0800 Subject: [PATCH 14/27] Rename CHNAGE_LIBRARY->CHANGE_PLAYGROUND_EXTERNAL --- src/actions/actionTypes.ts | 2 +- src/actions/workspaces.ts | 9 ++++----- src/reducers/workspaces.ts | 14 +++----------- src/sagas/index.ts | 14 +++++++++----- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/actions/actionTypes.ts b/src/actions/actionTypes.ts index ec6669d687..6a91c8ee5e 100644 --- a/src/actions/actionTypes.ts +++ b/src/actions/actionTypes.ts @@ -21,8 +21,8 @@ export const END_INTERRUPT_EXECUTION = 'END_INTERRUPT_EXECUTION' /** Workspace */ export const CHANGE_ACTIVE_TAB = 'CHANGE_ACTIVE_TAB' export const CHANGE_CHAPTER = 'CHANGE_CHAPTER' -export const CHANGE_LIBRARY = 'CHANGE_LIBRARY' export const CHANGE_EDITOR_WIDTH = 'CHANGE_EDITOR_WIDTH' +export const CHANGE_PLAYGROUND_EXTERNAL = 'CHANGE_PLAYGROUND_EXTERNAL' export const CHANGE_SIDE_CONTENT_HEIGHT = 'CHANGE_SIDE_CONTENT_HEIGHT' export const CHAPTER_SELECT = 'CHAPTER_SELECT' export const LIBRARY_SELECT = 'LIBRARY_SELECT' diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index d87f52fb80..55033e0416 100644 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -33,12 +33,11 @@ export const changeChapter: ActionCreator = ( payload: { newChapter, workspaceLocation } }) -export const changeLibrary: ActionCreator = ( - newLibrary: string, - workspaceLocation: WorkspaceLocation +export const changePlaygroundExternal: ActionCreator = ( + newExternal: string, ) => ({ - type: actionTypes.CHANGE_LIBRARY, - payload: { newLibrary, workspaceLocation } + type: actionTypes.CHANGE_PLAYGROUND_EXTERNAL, + payload: { newExternal } }) export const changeEditorWidth: ActionCreator = ( diff --git a/src/reducers/workspaces.ts b/src/reducers/workspaces.ts index 14c010cee0..bfa96a4065 100644 --- a/src/reducers/workspaces.ts +++ b/src/reducers/workspaces.ts @@ -124,20 +124,12 @@ export const reducer: Reducer = ( } } /** - * This action is only meant for Playground usage, - * as external library is specified by an individual question for an - * Assessment. + * This action is only meant for Playground usage, where the library is displayed. */ - case CHANGE_LIBRARY: - chapter = state[location].context.chapter - externals = externalLibraries.get(action.payload.newLibrary) || [] + case CHANGE_PLAYGROUND_EXTERNAL: return { ...state, - [location]: { - ...state[location], - context: createContext(chapter, externals, location) - }, - playgroundLibrary: action.payload.newLibrary + playgroundExternal: action.payload.newExternal } case HANDLE_CONSOLE_LOG: /* Possible cases: diff --git a/src/sagas/index.ts b/src/sagas/index.ts index ac9ae09286..1d44a9b052 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -10,7 +10,7 @@ import * as actionTypes from '../actions/actionTypes' import { WorkspaceLocation } from '../actions/workspaces' import { mockAssessmentOverviews, mockAssessments } from '../mocks/assessmentAPI' import { mockFetchGrading, mockFetchGradingOverview } from '../mocks/gradingAPI' -import { defaultEditorValue, IState } from '../reducers/states' +import { defaultEditorValue, externalLibraries, IState } from '../reducers/states' import { IVLE_KEY } from '../utils/constants' import { showSuccessMessage, showWarningMessage } from '../utils/notification' import backendSaga from './backend' @@ -105,21 +105,25 @@ function* workspaceSaga(): SagaIterator { }) /** - * Note that the LIBRARY_SELECT action can only select the library for playground. + * Note that the PLAYGROUND_EXTERNAL_SELECT action is made to + * select the library for playground. * This is because assessments do not have a chapter & library select, the question * specifies the chapter and library to be used. * * To abstract this to assessments, the state structure must be manipulated to store - * Library in a IWorkspaceState (as compared to IWorkspaceManagerState). + * the external library name in a IWorkspaceState (as compared to IWorkspaceManagerState). * * @see IWorkspaceManagerState @see IWorkspaceState */ - yield takeEvery(actionTypes.LIBRARY_SELECT, function*(action) { + yield takeEvery(actionTypes.EXTERNAL_SELECT, function*(action) { const location = (action as actionTypes.IAction).payload.workspaceLocation + const chapter = yield select((state: IState) => state.workspaces[location].context.chapter) const newLibrary = (action as actionTypes.IAction).payload.library const oldLibrary = yield select((state: IState) => state.workspaces.playgroundLibrary) if (newLibrary !== oldLibrary) { - yield put(actions.changeLibrary(newLibrary, location)) + const externals = externalLibraries.get(newLibrary)! + yield put(actions.changePlaygroundExternal(newLibrary)) + yield put(actions.clearContext(location, chapter, externals)) yield put(actions.clearReplOutput(location)) yield call(showSuccessMessage, `Switched to ${newLibrary} library`) } From 0b854acaee05388a8547cbf152dfadeeb93113a5 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 13:18:11 +0800 Subject: [PATCH 15/27] Add handleClearContext in GradingWorkspaceCont Overdue --- src/containers/academy/grading/GradingWorkspaceContainer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/containers/academy/grading/GradingWorkspaceContainer.ts b/src/containers/academy/grading/GradingWorkspaceContainer.ts index c5d92aeb37..930a106ec0 100644 --- a/src/containers/academy/grading/GradingWorkspaceContainer.ts +++ b/src/containers/academy/grading/GradingWorkspaceContainer.ts @@ -15,7 +15,7 @@ import { updateReplValue, WorkspaceLocation } from '../../../actions' -import { resetAssessmentWorkspace, updateCurrentSubmissionId } from '../../../actions/workspaces' +import { clearContext, resetAssessmentWorkspace, updateCurrentSubmissionId } from '../../../actions/workspaces' import GradingWorkspace, { DispatchProps, OwnProps, @@ -52,6 +52,7 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Dis handleChangeActiveTab: (activeTab: number) => changeActiveTab(activeTab, location), handleChapterSelect: (chapter: any, changeEvent: any) => chapterSelect(chapter, changeEvent, location), + handleClearContext: (chapter: number, externals: string[]) => clearContext(location, chapter, externals), handleEditorEval: () => evalEditor(location), handleEditorValueChange: (val: string) => updateEditorValue(val, location), handleEditorWidthChange: (widthChange: number) => changeEditorWidth(widthChange, location), From 0156a53a84e0b2b6611130b0a95e532e429a50c7 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 14:18:13 +0800 Subject: [PATCH 16/27] Change playground dispatch props --- src/components/Playground.tsx | 2 +- src/components/__tests__/Playground.tsx | 2 +- src/containers/PlaygroundContainer.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Playground.tsx b/src/components/Playground.tsx index 82bd9e5f56..b54f32c241 100644 --- a/src/components/Playground.tsx +++ b/src/components/Playground.tsx @@ -31,7 +31,7 @@ export interface IDispatchProps { handleEditorWidthChange: (widthChange: number) => void handleGenerateLz: () => void handleInterruptEval: () => void - handleLibrarySelect: (library: any, changeEvent: any) => void + handleExternalSelect: (external: any, changeEvent: any) => void handleReplEval: () => void handleReplOutputClear: () => void handleReplValueChange: (newValue: string) => void diff --git a/src/components/__tests__/Playground.tsx b/src/components/__tests__/Playground.tsx index bc50fabae7..c3250b9037 100644 --- a/src/components/__tests__/Playground.tsx +++ b/src/components/__tests__/Playground.tsx @@ -16,7 +16,7 @@ const baseProps = { output: [], replValue: '', handleChapterSelect: (chapter: any, e: any) => {}, - handleLibrarySelect: (library: any, e: any) => {}, + handleExternalSelect: (external: any, e: any) => {}, handleChangeActiveTab: (n: number) => {}, handleEditorEval: () => {}, handleEditorValueChange: () => {}, diff --git a/src/containers/PlaygroundContainer.ts b/src/containers/PlaygroundContainer.ts index 1feb54f788..47fbced958 100644 --- a/src/containers/PlaygroundContainer.ts +++ b/src/containers/PlaygroundContainer.ts @@ -12,7 +12,7 @@ import { evalEditor, evalRepl, generateLzString, - librarySelect, + playgroundExternalSelect, updateEditorValue, updateReplValue, WorkspaceLocation @@ -46,8 +46,8 @@ const mapDispatchToProps: MapDispatchToProps = (dispatch: Di handleEditorWidthChange: (widthChange: number) => changeEditorWidth(widthChange, location), handleGenerateLz: generateLzString, handleInterruptEval: () => beginInterruptExecution(location), - handleLibrarySelect: (library: any, changeEvent: any) => - librarySelect(library, changeEvent, location), + handleExternalSelect: (external: any, changeEvent: any) => + playgroundExternalSelect(external, changeEvent, location), handleReplEval: () => evalRepl(location), handleReplOutputClear: () => clearReplOutput(location), handleReplValueChange: (newValue: string) => updateReplValue(newValue, location), From 8e24fa016e81d8fe6acc2d3aa0439f3a49e8846d Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 14:18:29 +0800 Subject: [PATCH 17/27] Rename LIBRARY_SELECT action --- src/actions/actionTypes.ts | 2 +- src/actions/workspaces.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/actions/actionTypes.ts b/src/actions/actionTypes.ts index 6a91c8ee5e..3ed7c5a3ac 100644 --- a/src/actions/actionTypes.ts +++ b/src/actions/actionTypes.ts @@ -25,7 +25,7 @@ export const CHANGE_EDITOR_WIDTH = 'CHANGE_EDITOR_WIDTH' export const CHANGE_PLAYGROUND_EXTERNAL = 'CHANGE_PLAYGROUND_EXTERNAL' export const CHANGE_SIDE_CONTENT_HEIGHT = 'CHANGE_SIDE_CONTENT_HEIGHT' export const CHAPTER_SELECT = 'CHAPTER_SELECT' -export const LIBRARY_SELECT = 'LIBRARY_SELECT' +export const PLAYGROUND_EXTERNAL_SELECT = 'PLAYGROUND_EXTERNAL_SELECT ' export const CLEAR_REPL_INPUT = 'CLEAR_REPL_INPUT' export const CLEAR_REPL_OUTPUT = 'CLEAR_REPL_OUTPUT' export const CLEAR_CONTEXT = 'CLEAR_CONTEXT' diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index 55033e0416..57915619b0 100644 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -68,14 +68,14 @@ export const chapterSelect: ActionCreator = ( } }) -export const librarySelect: ActionCreator = ( - library, +export const playgroundExternalSelect: ActionCreator = ( + external, changeEvent, workspaceLocation: WorkspaceLocation ) => ({ - type: actionTypes.LIBRARY_SELECT, + type: actionTypes.PLAYGROUND_EXTERNAL_SELECT, payload: { - library: library.displayName, + external: external.displayName, workspaceLocation } }) From 1e28d1027f24535ea2260cfa6a031a91a9e35c0b Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 14:18:42 +0800 Subject: [PATCH 18/27] Use clearContext for external select saga --- src/sagas/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sagas/index.ts b/src/sagas/index.ts index 1d44a9b052..ada2d7a968 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -115,11 +115,11 @@ function* workspaceSaga(): SagaIterator { * * @see IWorkspaceManagerState @see IWorkspaceState */ - yield takeEvery(actionTypes.EXTERNAL_SELECT, function*(action) { + yield takeEvery(actionTypes.PLAYGROUND_EXTERNAL_SELECT, function*(action) { const location = (action as actionTypes.IAction).payload.workspaceLocation const chapter = yield select((state: IState) => state.workspaces[location].context.chapter) - const newLibrary = (action as actionTypes.IAction).payload.library - const oldLibrary = yield select((state: IState) => state.workspaces.playgroundLibrary) + const newExternal = (action as actionTypes.IAction).payload.external + const oldExternal = yield select((state: IState) => state.workspaces.playgroundExternal) if (newLibrary !== oldLibrary) { const externals = externalLibraries.get(newLibrary)! yield put(actions.changePlaygroundExternal(newLibrary)) From 0d64e050e14483aeaa058ee37de445819c964b35 Mon Sep 17 00:00:00 2001 From: remo5000 Date: Mon, 16 Jul 2018 14:34:05 +0800 Subject: [PATCH 19/27] Modify props and interfaces in components In Playground and ControlBar, rename all terms iwth Library to external/externals --- src/components/Playground.tsx | 4 +-- src/components/workspace/ControlBar.tsx | 36 ++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/components/Playground.tsx b/src/components/Playground.tsx index b54f32c241..43fb7942af 100644 --- a/src/components/Playground.tsx +++ b/src/components/Playground.tsx @@ -56,8 +56,9 @@ class Playground extends React.Component { public render() { const workspaceProps: WorkspaceProps = { controlBarProps: { + externalLibrary: this.props.externalLibrary, handleChapterSelect: this.props.handleChapterSelect, - handleLibrarySelect: this.props.handleLibrarySelect, + handleExternalSelect: this.props.handleExternalSelect, handleEditorEval: this.props.handleEditorEval, handleGenerateLz: this.props.handleGenerateLz, handleInterruptEval: this.props.handleInterruptEval, @@ -72,7 +73,6 @@ class Playground extends React.Component { isRunning: this.props.isRunning, queryString: this.props.queryString, sourceChapter: this.props.sourceChapter, - externalLibrary: this.props.externalLibrary }, editorProps: { editorValue: this.props.editorValue, diff --git a/src/components/workspace/ControlBar.tsx b/src/components/workspace/ControlBar.tsx index 305221cb9e..e143325e83 100644 --- a/src/components/workspace/ControlBar.tsx +++ b/src/components/workspace/ControlBar.tsx @@ -19,7 +19,7 @@ export type ControlBarProps = { sourceChapter: number externalLibrary?: string handleChapterSelect?: (i: IChapter, e: React.ChangeEvent) => void - handleLibrarySelect?: (i: ILibrary, e: React.ChangeEvent) => void + handleExternalSelect?: (i: IExternal, e: React.ChangeEvent) => void handleEditorEval: () => void handleGenerateLz?: () => void handleInterruptEval: () => void @@ -37,11 +37,11 @@ interface IChapter { } /** - * Defined for displaying a library. + * Defined for displaying an external library. * @see Library under assessmentShape.ts for * the definition of a Library in an assessment. */ -interface ILibrary { +interface IExternal { key: number displayName: string externals: string[] @@ -118,14 +118,14 @@ class ControlBar extends React.PureComponent { const chapterSelectButton = this.props.hasChapterSelect ? chapterSelect(this.props.sourceChapter, this.props.handleChapterSelect) : undefined - const librarySelectButton = + const externalSelectButton = this.props.hasChapterSelect && this.props.externalLibrary !== undefined - ? librarySelect(this.props.externalLibrary, this.props.handleLibrarySelect) + ? externalSelect(this.props.externalLibrary, this.props.handleExternalSelect) : undefined return (
{this.props.isRunning ? stopButton : runButton} {saveButton} - {shareButton} {chapterSelectButton} {librarySelectButton} + {shareButton} {chapterSelectButton} {externalSelectButton}
) } @@ -201,31 +201,31 @@ const chapterRenderer: ItemRenderer = (chap, { handleClick, modifiers, ) -const libraries = Array.from(externalLibraries.entries()).map((entry, index) => ({ +const externals = Array.from(externalLibraries.entries()).map((entry, index) => ({ displayName: entry[0], key: index, externals: entry[1] })) -const librarySelect = ( - currentLibrary: string, - handleSelect = (i: ILibrary, e: React.ChangeEvent) => {} +const externalSelect = ( + currentExternal: string, + handleSelect = (i: IExternal, e: React.ChangeEvent) => {} ) => ( - -