From fc1b898c80b30750ca0466306b8153f5510c1f15 Mon Sep 17 00:00:00 2001 From: Delucse <46593742+Delucse@users.noreply.github.com> Date: Sun, 20 Sep 2020 13:48:19 +0200 Subject: [PATCH] upload JSON string --- src/actions/tutorialBuilderActions.js | 9 +- src/actions/types.js | 1 + src/components/Compile.js | 36 ++++---- src/components/Dialog.js | 38 ++++++++ .../Tutorial/Builder/BlocklyExample.js | 82 +++++++++-------- src/components/Tutorial/Builder/Builder.js | 91 ++++++++++++++----- src/components/Tutorial/Builder/Textfield.js | 12 ++- src/components/Tutorial/Hardware.js | 65 ++++++------- src/components/Tutorial/SolutionCheck.js | 77 ++++++++-------- src/components/WorkspaceFunc.js | 37 ++++---- src/reducers/tutorialBuilderReducer.js | 8 +- 11 files changed, 272 insertions(+), 184 deletions(-) create mode 100644 src/components/Dialog.js diff --git a/src/actions/tutorialBuilderActions.js b/src/actions/tutorialBuilderActions.js index 25304c8..2f0f7ff 100644 --- a/src/actions/tutorialBuilderActions.js +++ b/src/actions/tutorialBuilderActions.js @@ -1,4 +1,4 @@ -import { PROGRESS, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types'; +import { PROGRESS, JSON_STRING, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP, BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from './types'; import data from '../data/hardware.json'; @@ -8,6 +8,13 @@ export const changeTutorialBuilder = () => (dispatch) => { }); }; +export const jsonString = (json) => (dispatch) => { + dispatch({ + type: JSON_STRING, + payload: json + }); +}; + export const tutorialTitle = (title) => (dispatch) => { dispatch({ type: BUILDER_TITLE, diff --git a/src/actions/types.js b/src/actions/types.js index e31e72f..0a1dc72 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -14,6 +14,7 @@ export const TUTORIAL_CHANGE = 'TUTORIAL_CHANGE'; export const TUTORIAL_XML = 'TUTORIAL_XML'; export const TUTORIAL_ID = 'TUTORIAL_ID'; export const TUTORIAL_STEP = 'TUTORIAL_STEP'; +export const JSON_STRING = 'JSON_STRING'; export const BUILDER_CHANGE = 'BUILDER_CHANGE'; diff --git a/src/components/Compile.js b/src/components/Compile.js index f1945f6..accde11 100644 --- a/src/components/Compile.js +++ b/src/components/Compile.js @@ -5,14 +5,12 @@ import { workspaceName } from '../actions/workspaceActions'; import { detectWhitespacesAndReturnReadableResult } from '../helpers/whitespace'; +import Dialog from './Dialog'; + import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import Backdrop from '@material-ui/core/Backdrop'; import CircularProgress from '@material-ui/core/CircularProgress'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogActions from '@material-ui/core/DialogActions'; -import Dialog from '@material-ui/core/Dialog'; import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import TextField from '@material-ui/core/TextField'; @@ -129,22 +127,20 @@ class Compile extends Component { - - {this.state.title} - - {this.state.content} - {this.state.file ? - - - this.download()}>Eingabe - - : null} - - - {this.toggleDialog(); this.setState({name: this.props.name})} : this.toggleDialog} color="primary"> - {this.state.file ? 'Abbrechen' : 'Schließen'} - - + {this.toggleDialog(); this.setState({name: this.props.name})} : this.toggleDialog} + button={this.state.file ? 'Abbrechen' : 'Schließen'} + > + {this.state.file ? + + + this.download()}>Eingabe + + : null} ); diff --git a/src/components/Dialog.js b/src/components/Dialog.js new file mode 100644 index 0000000..0dc7180 --- /dev/null +++ b/src/components/Dialog.js @@ -0,0 +1,38 @@ +import React, { Component } from 'react'; + +import Button from '@material-ui/core/Button'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogActions from '@material-ui/core/DialogActions'; +import MaterialUIDialog from '@material-ui/core/Dialog'; + +class Dialog extends Component { + + render() { + return ( + + {this.props.title} + + {this.props.content} + {this.props.children} + + + {this.props.actions ? this.props.actions : + + {this.props.button} + + } + + + ); + }; +} + + +export default Dialog; diff --git a/src/components/Tutorial/Builder/BlocklyExample.js b/src/components/Tutorial/Builder/BlocklyExample.js index be7d6f5..1714a76 100644 --- a/src/components/Tutorial/Builder/BlocklyExample.js +++ b/src/components/Tutorial/Builder/BlocklyExample.js @@ -7,13 +7,13 @@ import moment from 'moment'; import localization from 'moment/locale/de'; import * as Blockly from 'blockly/core'; -import { parseXml } from '../../../helpers/compareXml'; import BlocklyWindow from '../../Blockly/BlocklyWindow'; import { withStyles } from '@material-ui/core/styles'; import Switch from '@material-ui/core/Switch'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormHelperText from '@material-ui/core/FormHelperText'; +import FormLabel from '@material-ui/core/FormLabel'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; @@ -79,54 +79,56 @@ class BlocklyExample extends Component { } } - render() { moment.locale('de', localization); - var initialXml = this.props.value; - // check if value is valid xml; - try{ - Blockly.Xml.textToDom(initialXml); - } - catch(err){ - initialXml = null; - this.props.setError(this.props.index, 'xml'); - } return ( - this.onChange(e.target.checked)} - color="primary" - /> - } - /> + {!this.props.task ? + this.onChange(e.target.checked)} + color="primary" + /> + } + /> + : Musterlösung} {this.state.checked ? !this.props.value || this.props.error.steps[this.props.index].xml ? Reiche deine Blöcke ein, indem du auf den rot gefärbten Button klickst. : Die letzte Einreichung erfolgte um {this.state.input} Uhr. : null} - {this.state.checked ? - - - - + {this.state.checked ? (() => { + var initialXml = this.props.value; + // check if value is valid xml; + try{ + Blockly.Xml.textToDom(initialXml); + } + catch(err){ + initialXml = null; + this.props.setError(this.props.index, 'xml'); + } + return ( + + + + + - - {this.props.changeContent(this.props.index, 'xml', this.props.xml); this.setState({input: moment(Date.now()).format('LTS')})}} - > - {this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'} - - + {this.props.changeContent(this.props.index, 'xml', this.props.xml); this.setState({input: moment(Date.now()).format('LTS')})}} + > + {this.props.task ? 'Musterlösung einreichen' : 'Beispiel einreichen'} + + + )})() : null} ); diff --git a/src/components/Tutorial/Builder/Builder.js b/src/components/Tutorial/Builder/Builder.js index 130be52..94f88ec 100644 --- a/src/components/Tutorial/Builder/Builder.js +++ b/src/components/Tutorial/Builder/Builder.js @@ -1,17 +1,17 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { checkError, readJSON, progress, resetTutorial } from '../../../actions/tutorialBuilderActions'; +import { checkError, readJSON, jsonString, progress, resetTutorial } from '../../../actions/tutorialBuilderActions'; import { saveAs } from 'file-saver'; -import data from '../../../data/hardware.json'; import { detectWhitespacesAndReturnReadableResult } from '../../../helpers/whitespace'; import Breadcrumbs from '../../Breadcrumbs'; import Id from './Id'; -import Title from './Textfield'; +import Textfield from './Textfield'; import Step from './Step'; +import Dialog from '../../Dialog'; import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; @@ -30,6 +30,12 @@ class Builder extends Component { constructor(props){ super(props); + this.state = { + open: false, + title: '', + content: '', + string: false + }; this.inputRef = React.createRef(); } @@ -57,30 +63,37 @@ class Builder extends Component { uploadJsonFile = (jsonFile) => { this.props.progress(true); if(jsonFile.type !== 'application/json'){ - alert('falscher Dateityp'); this.props.progress(false); - this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur JSON-Dateien zulässig.' }); + this.setState({ open: true, string: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entspricht nicht dem geforderten Format. Es sind nur JSON-Dateien zulässig.'}); } else { var reader = new FileReader(); reader.readAsText(jsonFile); reader.onloadend = () => { - try { - var result = JSON.parse(reader.result); - if(!this.checkSteps(result.steps)){ - result.steps = [{}]; - } - this.props.readJSON(result); - } catch(err){ - console.log(err); - this.props.progress(false); - alert('ungültige JSON-Datei'); - this.setState({ open: true, file: false, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' }); - } + this.readJson(reader.result, true); }; } } + uploadJsonString = () => { + this.setState({ open: true, string: true, title: 'JSON-String einfügen', content: ''}); + } + + readJson = (jsonString, isFile) => { + try { + var result = JSON.parse(jsonString); + if(!this.checkSteps(result.steps)){ + result.steps = [{}]; + } + this.props.readJSON(result); + } catch(err){ + console.log(err); + this.props.progress(false); + this.props.jsonString(''); + this.setState({ open: true, string: false, title: 'Ungültiges JSON-Format', content: `${isFile ? 'Die übergebene Datei' : 'Der übergebene String'} enthält nicht valides JSON. Bitte überprüfe ${isFile ? 'die JSON-Datei' : 'den JSON-String'} und versuche es erneut.`}); + } + } + checkSteps = (steps) => { if(!(steps && steps.length > 0)){ return false; @@ -88,6 +101,10 @@ class Builder extends Component { return true; } + toggle = () => { + this.setState({ open: !this.state }); + } + render() { return ( @@ -96,6 +113,7 @@ class Builder extends Component { Tutorial-Builder + {/*upload JSON*/} Datei laden + this.uploadJsonString()}>String laden + {/*Tutorial-Builder-Form*/} - + {this.props.steps.map((step, i) => - )} - + {/*submit or reset*/} this.submit()}>Tutorial-Vorlage erstellen this.reset()}>Zurücksetzen + + + {this.toggle(); this.props.progress(true); this.readJson(this.props.json, false);}} color="primary">Bestätigen + {this.toggle(); this.props.jsonString('');}} color="primary">Abbrechen + + : null + } + > + {this.state.string ? + + : null} + - /* - Tutorial-Builder - - */ ); }; } @@ -138,12 +176,14 @@ class Builder extends Component { Builder.propTypes = { checkError: PropTypes.func.isRequired, readJSON: PropTypes.func.isRequired, + jsonString: PropTypes.func.isRequired, progress: PropTypes.func.isRequired, resetTutorial: PropTypes.func.isRequired, title: PropTypes.string.isRequired, steps: PropTypes.array.isRequired, change: PropTypes.number.isRequired, error: PropTypes.object.isRequired, + json: PropTypes.string.isRequired, isProgress: PropTypes.bool.isRequired }; @@ -153,7 +193,8 @@ const mapStateToProps = state => ({ steps: state.builder.steps, change: state.builder.change, error: state.builder.error, + json: state.builder.json, isProgress: state.builder.progress }); -export default connect(mapStateToProps, { checkError, readJSON, progress, resetTutorial })(withStyles(styles, {withTheme: true})(Builder)); +export default connect(mapStateToProps, { checkError, readJSON, jsonString, progress, resetTutorial })(withStyles(styles, {withTheme: true})(Builder)); diff --git a/src/components/Tutorial/Builder/Textfield.js b/src/components/Tutorial/Builder/Textfield.js index caeaba1..f2c88a8 100644 --- a/src/components/Tutorial/Builder/Textfield.js +++ b/src/components/Tutorial/Builder/Textfield.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { tutorialTitle, changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions'; +import { tutorialTitle, jsonString, changeContent, setError, deleteError } from '../../../actions/tutorialBuilderActions'; import { withStyles } from '@material-ui/core/styles'; import OutlinedInput from '@material-ui/core/OutlinedInput'; @@ -25,6 +25,9 @@ class Textfield extends Component { if(this.props.property === 'title'){ this.props.tutorialTitle(value); } + else if(this.props.property === 'json'){ + this.props.jsonString(value); + } else { this.props.changeContent(this.props.index, this.props.property, value); } @@ -55,7 +58,9 @@ class Textfield extends Component { {this.props.index !== undefined ? this.props.error.steps[this.props.index][this.props.property] ? {this.props.errorText} : null - : this.props.error[this.props.property] ? Gib einen Titel für das Tutorial ein. + : this.props.error[this.props.property] ? + this.props.property === 'title' ? Gib einen Titel für das Tutorial ein. + : Gib einen JSON-String ein und bestätige diesen mit einem Klick auf den entsprechenden Button : null} ); @@ -64,6 +69,7 @@ class Textfield extends Component { Textfield.propTypes = { tutorialTitle: PropTypes.func.isRequired, + jsonString: PropTypes.func.isRequired, changeContent: PropTypes.func.isRequired, error: PropTypes.object.isRequired, change: PropTypes.number.isRequired @@ -74,4 +80,4 @@ const mapStateToProps = state => ({ change: state.builder.change }); -export default connect(mapStateToProps, { tutorialTitle, changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(Textfield)); +export default connect(mapStateToProps, { tutorialTitle, jsonString, changeContent, setError, deleteError })(withStyles(styles, { withTheme: true })(Textfield)); diff --git a/src/components/Tutorial/Hardware.js b/src/components/Tutorial/Hardware.js index 614d6ae..b1c5351 100644 --- a/src/components/Tutorial/Hardware.js +++ b/src/components/Tutorial/Hardware.js @@ -1,18 +1,15 @@ import React, { Component } from 'react'; +import Dialog from '../Dialog'; + import { fade } from '@material-ui/core/styles/colorManipulator'; import { withStyles } from '@material-ui/core/styles'; import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; import Typography from '@material-ui/core/Typography'; import IconButton from '@material-ui/core/IconButton'; -import Button from '@material-ui/core/Button'; import GridList from '@material-ui/core/GridList'; import GridListTile from '@material-ui/core/GridListTile'; import GridListTileBar from '@material-ui/core/GridListTileBar'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faExpandAlt } from "@fortawesome/free-solid-svg-icons"; @@ -59,45 +56,41 @@ class Hardware extends Component { Für die Umsetzung benötigst du folgende Hardware: - - {this.props.picture.map((picture,i) => ( - - - this.handleClickOpen(picture, `/media/hardware/${picture}.png`)}/> + + {this.props.picture.map((picture,i) => ( + + + this.handleClickOpen(picture, `/media/hardware/${picture}.png`)}/> + + + {picture} - - {picture} - - } - actionIcon={ - this.handleClickOpen(picture, `/media/hardware/${picture}.png`)}> - - - } - /> - - ))} - + } + actionIcon={ + this.handleClickOpen(picture, `/media/hardware/${picture}.png`)}> + + + } + /> + + ))} + - Hardware: {this.state.title} - - - - - - Schließen - - + + ); }; diff --git a/src/components/Tutorial/SolutionCheck.js b/src/components/Tutorial/SolutionCheck.js index 084d2d1..0ab7252 100644 --- a/src/components/Tutorial/SolutionCheck.js +++ b/src/components/Tutorial/SolutionCheck.js @@ -6,6 +6,7 @@ import { tutorialCheck, tutorialStep } from '../../actions/tutorialActions'; import { withRouter } from 'react-router-dom'; import Compile from '../Compile'; +import Dialog from '../Dialog'; import tutorials from './tutorials.json'; import { checkXml } from '../../helpers/compareXml'; @@ -14,10 +15,7 @@ import { withStyles } from '@material-ui/core/styles'; import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import Button from '@material-ui/core/Button'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogActions from '@material-ui/core/DialogActions'; -import Dialog from '@material-ui/core/Dialog'; + import { faPlay } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -69,41 +67,44 @@ class SolutionCheck extends Component { - - {this.state.msg.type === 'error' ? 'Fehler' : 'Erfolg'} - - {this.state.msg.text} - {this.state.msg.type === 'success' ? - - - {this.props.activeStep === steps.length-1 ? - {this.toggleDialog(); this.props.history.push(`/tutorial/`)}} - > - Tutorials-Übersicht - - : - {this.toggleDialog(); this.props.tutorialStep(this.props.activeStep + 1)}} - > - nächster Schritt - - } - - : null} - - - - Schließen - - + + + {this.state.msg.type === 'success' ? + + + {this.props.activeStep === steps.length-1 ? + {this.toggleDialog(); this.props.history.push(`/tutorial/`)}} + > + Tutorials-Übersicht + + : + {this.toggleDialog(); this.props.tutorialStep(this.props.activeStep + 1)}} + > + nächster Schritt + + } + + : null} + ); }; diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js index 2beff96..3d413b3 100644 --- a/src/components/WorkspaceFunc.js +++ b/src/components/WorkspaceFunc.js @@ -12,14 +12,11 @@ import { initialXml } from './Blockly/initialXml.js'; import Compile from './Compile'; import SolutionCheck from './Tutorial/SolutionCheck'; +import Dialog from './Dialog'; import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogActions from '@material-ui/core/DialogActions'; -import Dialog from '@material-ui/core/Dialog'; import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import TextField from '@material-ui/core/TextField'; @@ -195,23 +192,23 @@ class WorkspaceFunc extends Component { - - {this.state.title} - - {this.state.content} - {this.state.file ? - - - {this.state.saveXml ? this.saveXmlFile() : this.props.workspaceName(this.state.name); this.toggleDialog();}}>Eingabe - - : null} - - - {this.toggleDialog(); this.setState({name: this.props.name})} : this.toggleDialog} color="primary"> - {this.state.file ? 'Abbrechen' : 'Schließen'} - - + + {this.toggleDialog(); this.setState({name: this.props.name})} : this.toggleDialog} + button={this.state.file ? 'Abbrechen' : 'Schließen'} + > + {this.state.file ? + + + {this.state.saveXml ? this.saveXmlFile() : this.props.workspaceName(this.state.name); this.toggleDialog();}}>Eingabe + + : null} + ); }; diff --git a/src/reducers/tutorialBuilderReducer.js b/src/reducers/tutorialBuilderReducer.js index 6296da2..132de0a 100644 --- a/src/reducers/tutorialBuilderReducer.js +++ b/src/reducers/tutorialBuilderReducer.js @@ -1,8 +1,9 @@ -import { PROGRESS, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP,BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from '../actions/types'; +import { PROGRESS, JSON_STRING, BUILDER_CHANGE, BUILDER_ERROR, BUILDER_TITLE, BUILDER_ID, BUILDER_ADD_STEP, BUILDER_DELETE_STEP, BUILDER_CHANGE_STEP,BUILDER_CHANGE_ORDER, BUILDER_DELETE_PROPERTY } from '../actions/types'; const initialState = { change: 0, progress: false, + json: '', title: '', id: '', steps: [ @@ -56,6 +57,11 @@ export default function(state = initialState, action){ ...state, progress: action.payload } + case JSON_STRING: + return { + ...state, + json: action.payload + } default: return state; }