diff --git a/src/actions/__tests__/workspaces.ts b/src/actions/__tests__/workspaces.ts index d9f9545400..a25d00e5b7 100755 --- a/src/actions/__tests__/workspaces.ts +++ b/src/actions/__tests__/workspaces.ts @@ -106,11 +106,13 @@ test('changeSideContentHeight generates correct action object', () => { test('chapterSelect generates correct action object', () => { const chapter = 3; - const action = chapterSelect(chapter, playgroundWorkspace); + const variant = 'default'; + const action = chapterSelect(chapter, variant, playgroundWorkspace); expect(action).toEqual({ type: actionTypes.CHAPTER_SELECT, payload: { chapter, + variant, workspaceLocation: playgroundWorkspace } }); diff --git a/src/actions/workspaces.ts b/src/actions/workspaces.ts index e8ed4676aa..0e98afbc1a 100755 --- a/src/actions/workspaces.ts +++ b/src/actions/workspaces.ts @@ -1,5 +1,6 @@ import { action } from 'typesafe-actions'; +import { Variant } from 'js-slang/dist/types'; import { ExternalLibraryName, Library } from '../components/assessment/assessmentShape'; import { IPosition } from '../components/workspace/Editor'; import { IWorkspaceState, SideContentType } from '../reducers/states'; @@ -46,9 +47,14 @@ export const changeExecTime = (execTime: string, workspaceLocation: WorkspaceLoc export const changeSideContentHeight = (height: number, workspaceLocation: WorkspaceLocation) => action(actionTypes.CHANGE_SIDE_CONTENT_HEIGHT, { height, workspaceLocation }); -export const chapterSelect = (chapter: number, workspaceLocation: WorkspaceLocation) => +export const chapterSelect = ( + chapter: number, + variant: Variant, + workspaceLocation: WorkspaceLocation +) => action(actionTypes.CHAPTER_SELECT, { chapter, + variant, workspaceLocation }); diff --git a/src/components/Application.tsx b/src/components/Application.tsx index 42062cdf0d..043833c1ad 100644 --- a/src/components/Application.tsx +++ b/src/components/Application.tsx @@ -9,18 +9,21 @@ import Material from '../containers/material/MaterialContainer'; import MissionControlContainer from '../containers/missionControl'; import Playground from '../containers/PlaygroundContainer'; import Sourcecast from '../containers/sourcecast/SourcecastContainer'; -import { Role, sourceChapters } from '../reducers/states'; +import { languageURLNames, Role } from '../reducers/states'; import { stringParamToInt } from '../utils/paramParseHelpers'; import { ExternalLibraryName, ExternalLibraryNames } from './assessment/assessmentShape'; import Contributors from './contributors'; import NavigationBar from './NavigationBar'; import NotFound from './NotFound'; +import { Variant } from 'js-slang/dist/types'; + export interface IApplicationProps extends IDispatchProps, IStateProps, RouteComponentProps<{}> {} export interface IStateProps { accessToken?: string; currentPlaygroundChapter: number; + currentPlaygroundVariant: Variant; role?: Role; title: string; name?: string; @@ -28,7 +31,11 @@ export interface IStateProps { } export interface IDispatchProps { - handleClearContext: (chapter: number, externalLibraryName: ExternalLibraryName) => void; + handleClearContext: ( + chapter: number, + variant: Variant, + externalLibraryName: ExternalLibraryName + ) => void; handleEditorValueChange: (val: string) => void; handleEditorUpdateBreakpoints: (breakpoints: string[]) => void; handleEnsureLibrariesLoaded: () => void; @@ -90,12 +97,13 @@ const toLogin = (props: IApplicationProps) => () => ( const parsePlayground = (props: IApplicationProps) => { const prgrm = parsePrgrm(props); const chapter = parseChapter(props) || props.currentPlaygroundChapter; + const variant = parseVariant(props) || props.currentPlaygroundVariant; const externalLibraryName = parseExternalLibrary(props) || props.currentExternalLibrary; const execTime = parseExecTime(props); if (prgrm) { props.handleEditorValueChange(prgrm); props.handleEnsureLibrariesLoaded(); - props.handleClearContext(chapter, externalLibraryName); + props.handleClearContext(chapter, variant, externalLibraryName); props.handleExternalLibrarySelect(externalLibraryName); props.handleSetExecTime(execTime); } @@ -112,8 +120,24 @@ const parsePrgrm = (props: RouteComponentProps<{}>) => { const parseChapter = (props: RouteComponentProps<{}>) => { const chapQuery = qs.parse(props.location.hash).chap; - const chap = chapQuery === undefined ? NaN : parseInt(chapQuery, 10); - return sourceChapters.includes(chap) ? chap : undefined; + + const chap: number = languageURLNames.has(chapQuery) + ? languageURLNames.get(chapQuery)!.chapter + : chapQuery === undefined + ? NaN + : parseInt(chapQuery, 10); + + return chap ? chap : undefined; +}; + +const parseVariant = (props: RouteComponentProps<{}>) => { + const chapQuery = qs.parse(props.location.hash).chap; + + const variant: Variant = languageURLNames.has(chapQuery) + ? languageURLNames.get(chapQuery)!.variant + : 'default'; + + return variant; }; const parseExternalLibrary = (props: RouteComponentProps<{}>) => { diff --git a/src/components/Playground.tsx b/src/components/Playground.tsx index fae7958ec9..74a40ac452 100755 --- a/src/components/Playground.tsx +++ b/src/components/Playground.tsx @@ -5,6 +5,7 @@ import * as React from 'react'; import { HotKeys } from 'react-hotkeys'; import { RouteComponentProps } from 'react-router'; +import { Variant } from 'js-slang/dist/types'; import { InterpreterOutput, SideContentType } from '../reducers/states'; import { LINKS } from '../utils/constants'; import { ExternalLibraryName, ExternalLibraryNames } from './assessment/assessmentShape'; @@ -70,6 +71,7 @@ export interface IStateProps { sharedbAceInitValue: string; sharedbAceIsInviting: boolean; sourceChapter: number; + sourceVariant: Variant; websocketStatus: number; externalLibraryName: string; usingSubst: boolean; @@ -80,7 +82,7 @@ export interface IDispatchProps { handleBrowseHistoryDown: () => void; handleBrowseHistoryUp: () => void; handleChangeExecTime: (execTime: number) => void; - handleChapterSelect: (chapter: number) => void; + handleChapterSelect: (chapter: number, variant: Variant) => void; handleDeclarationNavigate: (cursorPosition: IPosition) => void; handleEditorEval: () => void; handleEditorHeightChange: (height: number) => void; @@ -151,7 +153,10 @@ class Playground extends React.Component { /> ); - const chapterSelectHandler = ({ chapter }: { chapter: number }, e: any) => { + const chapterSelectHandler = ( + { chapter, variant }: { chapter: number; variant: Variant }, + e: any + ) => { if ( (chapter <= 2 && this.state.hasBreakpoints) || this.state.selectedTab === SideContentType.substVisualizer @@ -162,12 +167,13 @@ class Playground extends React.Component { this.props.handleReplOutputClear(); this.props.handleUsingSubst(false); } - this.props.handleChapterSelect(chapter); + this.props.handleChapterSelect(chapter, variant); }; const chapterSelect = ( ); diff --git a/src/components/__tests__/Application.tsx b/src/components/__tests__/Application.tsx index 7d8cc40d8f..a07d9a432e 100644 --- a/src/components/__tests__/Application.tsx +++ b/src/components/__tests__/Application.tsx @@ -5,14 +5,21 @@ import { mockRouterProps } from '../../mocks/components'; import Application, { IApplicationProps } from '../Application'; import { ExternalLibraryName, ExternalLibraryNames } from '../assessment/assessmentShape'; +import { Variant } from 'js-slang/dist/types'; + test('Application renders correctly', () => { const props: IApplicationProps = { ...mockRouterProps('/academy', {}), title: 'Cadet', currentPlaygroundChapter: 2, + currentPlaygroundVariant: 'default', handleLogOut: () => {}, currentExternalLibrary: ExternalLibraryNames.NONE, - handleClearContext: (chapter: number, externalLibraryName: ExternalLibraryName) => {}, + handleClearContext: ( + chapter: number, + variant: Variant, + externalLibraryName: ExternalLibraryName + ) => {}, handleEditorValueChange: (val: string) => {}, handleEditorUpdateBreakpoints: (breakpoints: string[]) => {}, handleEnsureLibrariesLoaded: () => {}, diff --git a/src/components/__tests__/Playground.tsx b/src/components/__tests__/Playground.tsx index 98f279e917..af451d2b3c 100755 --- a/src/components/__tests__/Playground.tsx +++ b/src/components/__tests__/Playground.tsx @@ -1,6 +1,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; +import { Variant } from 'js-slang/dist/types'; import { SideContentType } from 'src/reducers/states'; import { mockRouterProps } from '../../mocks/components'; import { ExternalLibraryName, ExternalLibraryNames } from '../assessment/assessmentShape'; @@ -22,6 +23,7 @@ const baseProps = { sharedbAceIsInviting: false, sideContentHeight: 40, sourceChapter: 2, + sourceVariant: 'default' as Variant, externalLibraryName: ExternalLibraryNames.NONE, output: [], replValue: '', diff --git a/src/components/assessment/assessmentShape.ts b/src/components/assessment/assessmentShape.ts index b8b731bf84..ef801ba028 100644 --- a/src/components/assessment/assessmentShape.ts +++ b/src/components/assessment/assessmentShape.ts @@ -1,4 +1,4 @@ -import { SourceError } from 'js-slang/dist/types'; +import { SourceError, Variant } from 'js-slang/dist/types'; /* * Used to display information regarding an assessment in the UI. @@ -166,6 +166,7 @@ type ExternalLibrary = { export type Library = { chapter: number; + variant?: Variant; external: ExternalLibrary; globals: Array<{ 0: string; diff --git a/src/components/missionControl/editingWorkspaceSideContent/DeploymentTab.tsx b/src/components/missionControl/editingWorkspaceSideContent/DeploymentTab.tsx index dd2a327701..b5e6e95fbe 100644 --- a/src/components/missionControl/editingWorkspaceSideContent/DeploymentTab.tsx +++ b/src/components/missionControl/editingWorkspaceSideContent/DeploymentTab.tsx @@ -3,7 +3,7 @@ import { IconNames } from '@blueprintjs/icons'; import { ItemRenderer, Select } from '@blueprintjs/select'; import * as React from 'react'; import { externalLibraries } from '../../../reducers/externalLibraries'; -import { sourceChapters } from '../../../reducers/states'; +import { sourceLanguages, styliseChapter } from '../../../reducers/states'; import { ExternalLibraryName, IAssessment, Library } from '../../assessment/assessmentShape'; import { controlButton } from '../../commons'; @@ -11,6 +11,8 @@ import { emptyLibrary } from '../assessmentTemplates'; import { assignToPath, getValueFromPath } from './'; import TextareaContent from './TextareaContent'; +import { Variant } from 'js-slang/dist/types'; + interface IProps { assessment: IAssessment; label: string; @@ -120,7 +122,7 @@ export class DeploymentTab extends React.Component { Interpreter:
- {chapterSelect(deployment.chapter, this.handleChapterSelect)} + {chapterSelect(deployment.chapter, deployment.variant, this.handleChapterSelect)} {symbolsFragment} @@ -240,14 +242,15 @@ const altEval = (str: string): any => { return Function('"use strict";return (' + str + ')')(); }; -function styliseChapter(chap: number) { - return `Source \xa7${chap}`; -} - -const chapters = sourceChapters.map(chap => ({ displayName: styliseChapter(chap), chapter: chap })); +const chapters = sourceLanguages.map(lang => ({ + chapter: lang.chapter, + variant: lang.variant, + displayName: styliseChapter(lang.chapter, lang.variant) +})); const chapterSelect = ( currentChap: number, + variant: Variant = 'default', handleSelect = (i: IChapter, e: React.ChangeEvent) => {} ) => (