From 8d729a0106ad78ef535e8ef50da888d012608ed3 Mon Sep 17 00:00:00 2001 From: Ger Hean Date: Wed, 20 Mar 2019 19:17:58 +0800 Subject: [PATCH 1/5] Update GlobalDeploymentTab.tsx nicer symbol editing --- .../GlobalDeploymentTab.tsx | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx b/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx index 643f9283a0..28f17760cc 100644 --- a/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx @@ -37,10 +37,14 @@ export class GlobalDeploymentTab extends React.Component { private deploymentTab = () => { const deployment = this.props.assessment.globalDeployment!; const symbols = deployment.external.symbols.map((symbol, i) => ( -
- {this.symbolTextareaContent(i)} -
-
+ + + {this.symbolTextareaContent(i)} + + + {controlButton('Delete', IconNames.MINUS, this.handleSymbolDelete(i))} + + )); return ( @@ -61,7 +65,9 @@ export class GlobalDeploymentTab extends React.Component { Symbols:

+ {symbols} +
{controlButton('New Symbol', IconNames.PLUS, this.handleNewSymbol)} ); @@ -88,6 +94,13 @@ export class GlobalDeploymentTab extends React.Component { this.props.updateAssessment(assessment); }; + private handleSymbolDelete = (index: number) => () => { + const assessment = this.props.assessment; + const symbols = assessment.globalDeployment!.external.symbols; + symbols.splice(index, 1); + this.props.updateAssessment(assessment); + }; + private handleNewSymbol = () => { const assessment = this.props.assessment; const symbols = assessment.globalDeployment!.external.symbols; @@ -104,6 +117,7 @@ export class GlobalDeploymentTab extends React.Component { private handleExternalSelect = (i: IExternal, e: React.ChangeEvent) => { const assessment = this.props.assessment; assessment.globalDeployment!.external.name = i.name; + assessment.globalDeployment!.external.symbols = externalLibraries.get(i.name)!; this.props.updateAssessment(assessment); }; } From 55c54d07ade0c6a6542be6f8da83e8a976676dd4 Mon Sep 17 00:00:00 2001 From: Ger Hean Date: Wed, 20 Mar 2019 21:17:16 +0800 Subject: [PATCH 2/5] nicer buttons --- .../incubator/ImportFromFileComponent.tsx | 32 ++++++++++++------- .../GlobalDeploymentTab.tsx | 18 ++++------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/components/incubator/ImportFromFileComponent.tsx b/src/components/incubator/ImportFromFileComponent.tsx index 46ae34b08c..cc0ae71a66 100644 --- a/src/components/incubator/ImportFromFileComponent.tsx +++ b/src/components/incubator/ImportFromFileComponent.tsx @@ -1,7 +1,10 @@ +import { FileInput } from '@blueprintjs/core'; +import { IconNames } from '@blueprintjs/icons'; import * as React from 'react'; import { parseString } from 'xml2js'; import { IAssessment, IAssessmentOverview } from '../../components/assessment/assessmentShape'; import { makeEntireAssessment, retrieveLocalAssessment } from '../../utils/xmlParser'; +import { controlButton } from '../commons'; import { assessmentTemplate, overviewTemplate } from '../incubator/assessmentTemplates'; type Props = { @@ -9,7 +12,11 @@ type Props = { updateEditingOverview: (overview: IAssessmentOverview) => void; }; -export class ImportFromFileComponent extends React.Component { +type State = { + fileInputText: string; +}; + +export class ImportFromFileComponent extends React.Component { private fileReader: FileReader; public constructor(props: any) { super(props); @@ -17,7 +24,7 @@ export class ImportFromFileComponent extends React.Component
Please ensure that the xml uploaded is trustable.
- - - {this.state.isInvalidXml ? ( -
The xml uploaded is invalid.
- ) : ( -
You can edit this card
- )} +
+ +
+
{controlButton('Make New Mission', IconNames.NEW_OBJECT, this.makeMission)}
); } @@ -57,13 +65,13 @@ export class ImportFromFileComponent extends React.Component { + private makeMission = () => { localStorage.setItem('MissionEditingOverviewSA', JSON.stringify(overviewTemplate)); this.props.updateEditingOverview(overviewTemplate); diff --git a/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx b/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx index 28f17760cc..c8799187e3 100644 --- a/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx @@ -38,12 +38,8 @@ export class GlobalDeploymentTab extends React.Component { const deployment = this.props.assessment.globalDeployment!; const symbols = deployment.external.symbols.map((symbol, i) => ( - - {this.symbolTextareaContent(i)} - - - {controlButton('Delete', IconNames.MINUS, this.handleSymbolDelete(i))} - + {this.symbolTextareaContent(i)} + {controlButton('Delete', IconNames.MINUS, this.handleSymbolDelete(i))} )); @@ -65,9 +61,7 @@ export class GlobalDeploymentTab extends React.Component { Symbols:

- - {symbols} -
+ {symbols}
{controlButton('New Symbol', IconNames.PLUS, this.handleNewSymbol)} ); @@ -95,7 +89,7 @@ export class GlobalDeploymentTab extends React.Component { }; private handleSymbolDelete = (index: number) => () => { - const assessment = this.props.assessment; + const assessment = this.props.assessment; const symbols = assessment.globalDeployment!.external.symbols; symbols.splice(index, 1); this.props.updateAssessment(assessment); @@ -117,7 +111,9 @@ export class GlobalDeploymentTab extends React.Component { private handleExternalSelect = (i: IExternal, e: React.ChangeEvent) => { const assessment = this.props.assessment; assessment.globalDeployment!.external.name = i.name; - assessment.globalDeployment!.external.symbols = externalLibraries.get(i.name)!; + assessment.globalDeployment!.external.symbols = JSON.parse( + JSON.stringify(externalLibraries.get(i.name)!) + ); this.props.updateAssessment(assessment); }; } From 2c2ba57a88d8ea4ad66a8334b854f095930d6149 Mon Sep 17 00:00:00 2001 From: Ger Hean Date: Thu, 21 Mar 2019 14:32:57 +0800 Subject: [PATCH 3/5] made local deployment and added globals editing --- src/components/incubator/EditingWorkspace.tsx | 20 +- .../incubator/assessmentTemplates.ts | 2 +- .../DeploymentTab.tsx | 264 ++++++++++++++++++ .../GlobalDeploymentTab.tsx | 179 ------------ .../TextareaContent.tsx | 4 + .../editingWorkspaceSideContent/index.tsx | 6 +- 6 files changed, 289 insertions(+), 186 deletions(-) create mode 100644 src/components/incubator/editingWorkspaceSideContent/DeploymentTab.tsx delete mode 100644 src/components/incubator/editingWorkspaceSideContent/GlobalDeploymentTab.tsx diff --git a/src/components/incubator/EditingWorkspace.tsx b/src/components/incubator/EditingWorkspace.tsx index f094553811..a0bfa6b4fe 100644 --- a/src/components/incubator/EditingWorkspace.tsx +++ b/src/components/incubator/EditingWorkspace.tsx @@ -19,7 +19,7 @@ import { ControlBarProps } from '../workspace/ControlBar'; import { SideContentProps } from '../workspace/side-content'; import ToneMatrix from '../workspace/side-content/ToneMatrix'; import { - GlobalDeploymentTab, + DeploymentTab, GradingTab, ManageQuestionTab, QuestionTemplateTab, @@ -293,11 +293,25 @@ class AssessmentWorkspace extends React.Component + ) + }, + { + label: `Manage Local Deployment`, + icon: IconNames.HOME, + body: ( + ) } diff --git a/src/components/incubator/assessmentTemplates.ts b/src/components/incubator/assessmentTemplates.ts index 423896f8d0..c8a3f56b5c 100644 --- a/src/components/incubator/assessmentTemplates.ts +++ b/src/components/incubator/assessmentTemplates.ts @@ -9,7 +9,7 @@ import { } from '../../components/assessment/assessmentShape'; import { mock2DRuneLibrary } from '../../mocks/assessmentAPI'; -const emptyLibrary: Library = { +export const emptyLibrary: Library = { chapter: -1, external: { name: 'NONE', diff --git a/src/components/incubator/editingWorkspaceSideContent/DeploymentTab.tsx b/src/components/incubator/editingWorkspaceSideContent/DeploymentTab.tsx new file mode 100644 index 0000000000..5fa5f9fbf0 --- /dev/null +++ b/src/components/incubator/editingWorkspaceSideContent/DeploymentTab.tsx @@ -0,0 +1,264 @@ +import { Button, MenuItem, Switch } from '@blueprintjs/core'; +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 { ExternalLibraryName, IAssessment, Library } from '../../assessment/assessmentShape'; +import { controlButton } from '../../commons'; +import { emptyLibrary } from '../assessmentTemplates'; +import { assignToPath, getValueFromPath } from './'; +import TextareaContent from './TextareaContent'; + +interface IProps { + assessment: IAssessment; + pathToLibrary: Array; + updateAssessment: (assessment: IAssessment) => void; + isGlobalDeployment: boolean; +} + +interface IChapter { + chapter: number; + displayName: string; +} + +interface IExternal { + key: number; + name: ExternalLibraryName; + symbols: string[]; +} + +export class DeploymentTab extends React.Component { + public constructor(props: IProps) { + super(props); + this.state = { + deploymentEnabled: false + }; + } + + public render() { + if(this.props.isGlobalDeployment) { + return this.deploymentTab(); + } else { + return
+ + {this.state.deploymentEnabled ? this.deploymentTab() : null} +
; + } + } + + private deploymentTab = () => { + const deploymentPath = this.props.pathToLibrary; + const deployment = getValueFromPath(deploymentPath, this.props.assessment) as Library; + const deploymentDisp = this.props.isGlobalDeployment ? "Global Deployment" : "Local Deployment"; + const symbols = deployment.external.symbols.map((symbol, i) => ( + + {this.textareaContent(deploymentPath.concat(['external', 'symbols', i]))} + {controlButton('Delete', IconNames.MINUS, this.handleSymbolDelete(i))} + + )); + const globals = deployment.globals.map((symbol, i) => ( + + {this.textareaContent(deploymentPath.concat(['globals', i, 0]))} + {this.globalValueTextareaContent(i)} + {controlButton('Delete', IconNames.MINUS, this.handleGlobalDelete(i))} + + )); + + return ( +
+ {deploymentDisp} +
+
+ Interpreter: +
+ {chapterSelect(deployment.chapter, this.handleChapterSelect)} +
+
+ External Library: +
+ {externalSelect(deployment.external.name, this.handleExternalSelect!)} +
+
+
Symbols:
+
+ {symbols}
+ {controlButton('New Symbol', IconNames.PLUS, this.handleNewSymbol)} +
+
+
Globals:
+
+ {globals}
+ {controlButton('New Global', IconNames.PLUS, this.handleNewGlobal)} +
+ ); + }; + + + private textareaContent = (path: Array) => { + return ( + + ); + }; + + private globalValueTextareaContent = (i: number) => { + const pathVal = this.props.pathToLibrary.concat(['globals', i, 2]); + return ( + + ); + }; + + private handleGlobalValueUpdate = (i: number) => (assessment: IAssessment) => { + const deployment = getValueFromPath(this.props.pathToLibrary, this.props.assessment) as Library; + const global = deployment.globals[i]; + try { + global[1] = altEval(global[2]!); + this.props.updateAssessment(assessment); + } catch (e) { + global[2] = "Invalid Expression"; + } + }; + + private handleSymbolDelete = (index: number) => () => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + const symbols = deployment.external.symbols; + symbols.splice(index, 1); + this.props.updateAssessment(assessment); + }; + + private handleNewSymbol = () => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + const symbols = deployment.external.symbols; + symbols.push('new symbol'); + this.props.updateAssessment(assessment); + }; + + private handleGlobalDelete = (index: number) => () => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + deployment.globals.splice(index, 1); + this.props.updateAssessment(assessment); + }; + + private handleNewGlobal = () => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + deployment.globals.push(["new_global", null, "null"]); + this.props.updateAssessment(assessment); + }; + + private handleChapterSelect = (i: IChapter, e: React.ChangeEvent) => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + deployment.chapter = i.chapter; + this.props.updateAssessment(assessment); + }; + + private handleExternalSelect = (i: IExternal, e: React.ChangeEvent) => { + const assessment = this.props.assessment; + const deployment = getValueFromPath(this.props.pathToLibrary, assessment) as Library; + deployment.external.name = i.name; + deployment.external.symbols = JSON.parse( + JSON.stringify(externalLibraries.get(i.name)!) + ); + this.props.updateAssessment(assessment); + }; + + private handleSwitchDeployment = () => { + const assessment = this.props.assessment; + if (this.state.deploymentEnabled) { + assignToPath(this.props.pathToLibrary, JSON.parse(JSON.stringify(emptyLibrary)), assessment); + } else { + assignToPath(this.props.pathToLibrary.concat(["chapter"]), 1, assessment); + } + this.setState({ + deploymentEnabled: !this.state.deploymentEnabled + }); + this.props.updateAssessment(assessment); + } +} + +const removeSpaces = (str: string) => { + return str.replace(/\s+/g, ''); +}; + +function styliseChapter(chap: number) { + return `Source \xa7${chap}`; +} + +const chapters = sourceChapters.map(chap => ({ displayName: styliseChapter(chap), chapter: chap })); + +const chapterSelect = ( + currentChap: number, + handleSelect = (i: IChapter, e: React.ChangeEvent) => {} +) => ( + +