Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@blueprintjs/popover2": "^1.4.3",
"@blueprintjs/select": "^4.5.1",
"@octokit/rest": "^19.0.5",
"@reduxjs/toolkit": "^1.9.3",
"@sentry/browser": "^7.8.0",
"@sourceacademy/sharedb-ace": "^2.0.2",
"@sourceacademy/sling-client": "^0.1.0",
Expand Down
51 changes: 34 additions & 17 deletions src/commons/application/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,26 @@ export enum Role {
Admin = 'admin'
}

export enum SupportedLanguage {
JAVASCRIPT = 'JavaScript',
SCHEME = 'Scheme',
PYTHON = 'Python'
}

export const SUPPORTED_LANGUAGES = [
SupportedLanguage.JAVASCRIPT,
SupportedLanguage.SCHEME,
SupportedLanguage.PYTHON
];

/**
* Defines the languages available for use on Source Academy,
* including Source sublanguages and other languages e.g. full JS.
* For external libraries, see ExternalLibrariesTypes.ts
*/
export interface SALanguage extends Language {
displayName: string;
mainLanguage: SupportedLanguage;
}

const variantDisplay: Map<Variant, string> = new Map([
Expand All @@ -126,37 +139,48 @@ const variantDisplay: Map<Variant, string> = new Map([
export const fullJSLanguage: SALanguage = {
chapter: Chapter.FULL_JS,
variant: Variant.DEFAULT,
displayName: 'full JavaScript'
displayName: 'full JavaScript',
mainLanguage: SupportedLanguage.JAVASCRIPT
};

export const fullTSLanguage: SALanguage = {
chapter: Chapter.FULL_TS,
variant: Variant.DEFAULT,
displayName: 'full TypeScript'
displayName: 'full TypeScript',
mainLanguage: SupportedLanguage.JAVASCRIPT
};

export const htmlLanguage: SALanguage = {
chapter: Chapter.HTML,
variant: Variant.DEFAULT,
displayName: 'HTML'
displayName: 'HTML',
mainLanguage: SupportedLanguage.JAVASCRIPT
};

export const schemeLanguages: SALanguage[] = [
const schemeSubLanguages = [
{ chapter: Chapter.SCHEME_1, variant: Variant.DEFAULT, displayName: 'Scheme \xa71' },
{ chapter: Chapter.SCHEME_2, variant: Variant.DEFAULT, displayName: 'Scheme \xa72' },
{ chapter: Chapter.SCHEME_3, variant: Variant.DEFAULT, displayName: 'Scheme \xa73' },
{ chapter: Chapter.SCHEME_4, variant: Variant.DEFAULT, displayName: 'Scheme \xa74' },
{ chapter: Chapter.FULL_SCHEME, variant: Variant.DEFAULT, displayName: 'Full Scheme' }
];

export const pyLanguages: SALanguage[] = [
export const schemeLanguages: SALanguage[] = schemeSubLanguages.map(sublang => {
return { ...sublang, mainLanguage: SupportedLanguage.SCHEME };
});

const pySubLanguages = [
{ chapter: Chapter.PYTHON_1, variant: Variant.DEFAULT, displayName: 'Python \xa71' }
//{ chapter: Chapter.PYTHON_2, variant: Variant.DEFAULT, displayName: 'Python \xa72' },
//{ chapter: Chapter.PYTHON_3, variant: Variant.DEFAULT, displayName: 'Python \xa73' },
//{ chapter: Chapter.PYTHON_4, variant: Variant.DEFAULT, displayName: 'Python \xa74' }
//{ chapter: Chapter.FULL_PYTHON, variant: Variant.DEFAULT, displayName: 'Full Python' }
];

export const pyLanguages: SALanguage[] = pySubLanguages.map(sublang => {
return { ...sublang, mainLanguage: SupportedLanguage.PYTHON };
});

export const styliseSublanguage = (chapter: Chapter, variant: Variant = Variant.DEFAULT) => {
switch (chapter) {
case Chapter.FULL_JS:
Expand All @@ -183,7 +207,7 @@ export const styliseSublanguage = (chapter: Chapter, variant: Variant = Variant.
}
};

export const sublanguages: Language[] = [
export const sourceSublanguages: Language[] = [
{ chapter: Chapter.SOURCE_1, variant: Variant.DEFAULT },
{ chapter: Chapter.SOURCE_1, variant: Variant.TYPED },
{ chapter: Chapter.SOURCE_1, variant: Variant.WASM },
Expand All @@ -205,21 +229,14 @@ export const sublanguages: Language[] = [
{ chapter: Chapter.SOURCE_4, variant: Variant.EXPLICIT_CONTROL }
];

export const sourceLanguages: SALanguage[] = sublanguages.map(sublang => {
export const sourceLanguages: SALanguage[] = sourceSublanguages.map(sublang => {
return {
...sublang,
displayName: styliseSublanguage(sublang.chapter, sublang.variant)
displayName: styliseSublanguage(sublang.chapter, sublang.variant),
mainLanguage: SupportedLanguage.JAVASCRIPT
};
});

export const defaultLanguages = sourceLanguages.filter(
sublang => sublang.variant === Variant.DEFAULT
);

export const variantLanguages = sourceLanguages.filter(
sublang => sublang.variant !== Variant.DEFAULT
);

export const isSourceLanguage = (chapter: Chapter) =>
[Chapter.SOURCE_1, Chapter.SOURCE_2, Chapter.SOURCE_3, Chapter.SOURCE_4].includes(chapter);

Expand Down Expand Up @@ -258,7 +275,7 @@ export const defaultAchievement: AchievementState = {

export const defaultPlayground: PlaygroundState = {
githubSaveInfo: { repoName: '', filePath: '' },
lang: 'JavaScript'
lang: SupportedLanguage.JAVASCRIPT
};

export const defaultEditorValue = '// Type your program in here!';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ exports[`AssessmentWorkspace page with ContestVoting question renders correctly
</ControlButton>
</ControlBarResetButton>
<ControlBarChapterSelect handleChapterSelect={[Function: handleChapterSelect]} isFolderModeEnabled={false} sourceChapter={1} sourceVariant=\\"default\\" disabled={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Popover autoFocus={false} enforceFocus={false} isOpen={false} disabled={true} position=\\"bottom-left\\" className=\\"\\" onInteraction={[Function (anonymous)]} popoverClassName=\\"bp4-select-popover\\" onOpening={[Function (anonymous)]} onOpened={[Function (anonymous)]} onClosing={[Function (anonymous)]} boundary=\\"scrollParent\\" captureDismiss={false} defaultIsOpen={false} fill={false} hasBackdrop={false} hoverCloseDelay={300} hoverOpenDelay={150} inheritDarkTheme={true} interactionKind=\\"click\\" minimal={false} modifiers={{...}} openOnTargetFocus={true} shouldReturnFocusOnClose={false} targetTagName=\\"span\\" transitionDuration={300} usePortal={true} wrapperTagName=\\"span\\">
<Manager>
<span className=\\"bp4-popover-wrapper\\">
Expand Down Expand Up @@ -889,8 +889,8 @@ exports[`AssessmentWorkspace page with MCQ question renders correctly 1`] = `
</Blueprint4.Tooltip2>
</ControlBarRunButton>
<ControlBarChapterSelect handleChapterSelect={[Function: handleChapterSelect]} isFolderModeEnabled={false} sourceChapter={1} sourceVariant=\\"default\\" disabled={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Popover autoFocus={false} enforceFocus={false} isOpen={false} disabled={true} position=\\"bottom-left\\" className=\\"\\" onInteraction={[Function (anonymous)]} popoverClassName=\\"bp4-select-popover\\" onOpening={[Function (anonymous)]} onOpened={[Function (anonymous)]} onClosing={[Function (anonymous)]} boundary=\\"scrollParent\\" captureDismiss={false} defaultIsOpen={false} fill={false} hasBackdrop={false} hoverCloseDelay={300} hoverOpenDelay={150} inheritDarkTheme={true} interactionKind=\\"click\\" minimal={false} modifiers={{...}} openOnTargetFocus={true} shouldReturnFocusOnClose={false} targetTagName=\\"span\\" transitionDuration={300} usePortal={true} wrapperTagName=\\"span\\">
<Manager>
<span className=\\"bp4-popover-wrapper\\">
Expand Down Expand Up @@ -1489,8 +1489,8 @@ exports[`AssessmentWorkspace page with overdue assessment renders correctly 1`]
</ControlButton>
</ControlBarResetButton>
<ControlBarChapterSelect handleChapterSelect={[Function: handleChapterSelect]} isFolderModeEnabled={false} sourceChapter={1} sourceVariant=\\"default\\" disabled={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Popover autoFocus={false} enforceFocus={false} isOpen={false} disabled={true} position=\\"bottom-left\\" className=\\"\\" onInteraction={[Function (anonymous)]} popoverClassName=\\"bp4-select-popover\\" onOpening={[Function (anonymous)]} onOpened={[Function (anonymous)]} onClosing={[Function (anonymous)]} boundary=\\"scrollParent\\" captureDismiss={false} defaultIsOpen={false} fill={false} hasBackdrop={false} hoverCloseDelay={300} hoverOpenDelay={150} inheritDarkTheme={true} interactionKind=\\"click\\" minimal={false} modifiers={{...}} openOnTargetFocus={true} shouldReturnFocusOnClose={false} targetTagName=\\"span\\" transitionDuration={300} usePortal={true} wrapperTagName=\\"span\\">
<Manager>
<span className=\\"bp4-popover-wrapper\\">
Expand Down Expand Up @@ -2045,8 +2045,8 @@ exports[`AssessmentWorkspace page with programming question renders correctly 1`
</ControlButton>
</ControlBarResetButton>
<ControlBarChapterSelect handleChapterSelect={[Function: handleChapterSelect]} isFolderModeEnabled={false} sourceChapter={1} sourceVariant=\\"default\\" disabled={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Popover autoFocus={false} enforceFocus={false} isOpen={false} disabled={true} position=\\"bottom-left\\" className=\\"\\" onInteraction={[Function (anonymous)]} popoverClassName=\\"bp4-select-popover\\" onOpening={[Function (anonymous)]} onOpened={[Function (anonymous)]} onClosing={[Function (anonymous)]} boundary=\\"scrollParent\\" captureDismiss={false} defaultIsOpen={false} fill={false} hasBackdrop={false} hoverCloseDelay={300} hoverOpenDelay={150} inheritDarkTheme={true} interactionKind=\\"click\\" minimal={false} modifiers={{...}} openOnTargetFocus={true} shouldReturnFocusOnClose={false} targetTagName=\\"span\\" transitionDuration={300} usePortal={true} wrapperTagName=\\"span\\">
<Manager>
<span className=\\"bp4-popover-wrapper\\">
Expand Down Expand Up @@ -2601,8 +2601,8 @@ exports[`AssessmentWorkspace renders Grading tab correctly if the question has b
</ControlButton>
</ControlBarResetButton>
<ControlBarChapterSelect handleChapterSelect={[Function: handleChapterSelect]} isFolderModeEnabled={false} sourceChapter={1} sourceVariant=\\"default\\" disabled={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRendererA]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Select items={{...}} onItemSelect={[Function: handleChapterSelect]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} filterable={false} disabled={true}>
<Blueprint4.QueryList items={{...}} onItemSelect={[Function (anonymous)]} itemRenderer={[Function (anonymous)]} itemListRenderer={[Function: chapterListRenderer]} disabled={true} renderer={[Function (anonymous)]} resetOnQuery={true}>
<Blueprint4.Popover autoFocus={false} enforceFocus={false} isOpen={false} disabled={true} position=\\"bottom-left\\" className=\\"\\" onInteraction={[Function (anonymous)]} popoverClassName=\\"bp4-select-popover\\" onOpening={[Function (anonymous)]} onOpened={[Function (anonymous)]} onClosing={[Function (anonymous)]} boundary=\\"scrollParent\\" captureDismiss={false} defaultIsOpen={false} fill={false} hasBackdrop={false} hoverCloseDelay={300} hoverOpenDelay={150} inheritDarkTheme={true} interactionKind=\\"click\\" minimal={false} modifiers={{...}} openOnTargetFocus={true} shouldReturnFocusOnClose={false} targetTagName=\\"span\\" transitionDuration={300} usePortal={true} wrapperTagName=\\"span\\">
<Manager>
<span className=\\"bp4-popover-wrapper\\">
Expand Down
80 changes: 24 additions & 56 deletions src/commons/controlBar/ControlBarChapterSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@ import { IconNames } from '@blueprintjs/icons';
import { Tooltip2 } from '@blueprintjs/popover2';
import { ItemListRenderer, ItemRenderer, Select } from '@blueprintjs/select';
import { Chapter, Variant } from 'js-slang/dist/types';
import React, { useEffect, useState } from 'react';
import { store } from 'src/pages/createStore';
import React from 'react';

import {
defaultLanguages,
fullJSLanguage,
fullTSLanguage,
htmlLanguage,
pyLanguages,
SALanguage,
schemeLanguages,
sourceLanguages,
styliseSublanguage,
variantLanguages
styliseSublanguage
} from '../application/ApplicationTypes';
import Constants from '../utils/Constants';
import { useTypedSelector } from '../utils/Hooks';

type ControlBarChapterSelectProps = DispatchProps & StateProps;

Expand All @@ -33,40 +31,22 @@ type StateProps = {
disabled?: boolean;
};

const chapterListRendererA: ItemListRenderer<SALanguage> = ({ itemsParentRef, renderItem }) => {
const defaultChoices = defaultLanguages.map(renderItem);
const variantChoices = variantLanguages.map(renderItem);
const fullJSChoice = renderItem(fullJSLanguage, 0);
const fullTSChoice = renderItem(fullTSLanguage, 0);
const htmlChoice = renderItem(htmlLanguage, 0);

return (
<Menu ulRef={itemsParentRef} style={{ display: 'flex', flexDirection: 'column' }}>
{defaultChoices}
{Constants.playgroundOnly && fullJSChoice}
{Constants.playgroundOnly && fullTSChoice}
{Constants.playgroundOnly && htmlChoice}
<MenuItem key="variant-menu" text="Variants" icon="cog">
{variantChoices}
</MenuItem>
</Menu>
);
};

const chapterListRendererB: ItemListRenderer<SALanguage> = ({ itemsParentRef, renderItem }) => {
const schemeChoice = schemeLanguages.map(renderItem);
return (
<Menu ulRef={itemsParentRef} style={{ display: 'flex', flexDirection: 'column' }}>
{Constants.playgroundOnly && schemeChoice}
</Menu>
);
};
const chapterListRenderer: ItemListRenderer<SALanguage> = ({
itemsParentRef,
renderItem,
items
}) => {
const defaultChoices = items.filter(({ variant }) => variant === Variant.DEFAULT);
const variantChoices = items.filter(({ variant }) => variant !== Variant.DEFAULT);

const chapterListRendererC: ItemListRenderer<SALanguage> = ({ itemsParentRef, renderItem }) => {
const pyChoice = pyLanguages.map(renderItem);
return (
<Menu ulRef={itemsParentRef} style={{ display: 'flex', flexDirection: 'column' }}>
{Constants.playgroundOnly && pyChoice}
{defaultChoices.map(renderItem)}
{variantChoices.length > 0 && (
<MenuItem key="variant-menu" text="Variants" icon="cog">
{variantChoices.map(renderItem)}
</MenuItem>
)}
</Menu>
);
};
Expand Down Expand Up @@ -98,30 +78,18 @@ export const ControlBarChapterSelect: React.FC<ControlBarChapterSelectProps> = (
handleChapterSelect = () => {},
disabled = false
}) => {
const [selectedLang, setSelectedLang] = useState(store.getState().playground.lang);
useEffect(() => {
const unsubscribe = store.subscribe(() => {
const newSelectedLang = store.getState().playground.lang;
setSelectedLang(newSelectedLang);
});
return () => {
unsubscribe();
};
}, []);

let chapterListRenderer: ItemListRenderer<SALanguage> = chapterListRendererA;
const selectedLang = useTypedSelector(store => store.playground.lang);

if (selectedLang === 'JavaScript') {
chapterListRenderer = chapterListRendererA;
} else if (selectedLang === 'Scheme') {
chapterListRenderer = chapterListRendererB;
} else if (selectedLang === 'Python') {
chapterListRenderer = chapterListRendererC;
}
const choices = [
...sourceLanguages,
...(Constants.playgroundOnly ? [fullJSLanguage, fullTSLanguage, htmlLanguage] : []),
...schemeLanguages,
...pyLanguages
];

return (
<ChapterSelectComponent
items={sourceLanguages}
items={choices.filter(({ mainLanguage }) => mainLanguage === selectedLang)}
onItemSelect={handleChapterSelect}
itemRenderer={chapterRenderer(isFolderModeEnabled)}
itemListRenderer={chapterListRenderer}
Expand Down
Loading