upload JSON file

This commit is contained in:
Delucse
2020-09-19 23:21:43 +02:00
parent 28ced177bd
commit 7579be52c9
7 changed files with 212 additions and 35 deletions
@@ -5,7 +5,9 @@ import { changeContent, deleteProperty, setError, deleteError } from '../../../a
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';
@@ -94,27 +96,38 @@ class BlocklyExample extends Component {
/>
}
/>
{this.state.checked ? !this.props.value ?
{this.state.checked ? !this.props.value || this.props.error.steps[this.props.index].xml ?
<FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}} className={this.props.classes.errorColor}>Reiche deine Blöcke ein, indem du auf den rot gefärbten Button klickst.</FormHelperText>
: <FormHelperText style={{lineHeight: 'initial', marginBottom: '10px'}}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText>
: null}
{this.state.checked ?
<div>
<Grid container className={!this.props.value ? this.props.classes.errorBorder : null}>
<Grid item xs={12}>
<BlocklyWindow initialXml={this.props.value}/>
{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(
<div>
<Grid container className={!this.props.value ? this.props.classes.errorBorder : null}>
<Grid item xs={12}>
<BlocklyWindow initialXml={initialXml}/>
</Grid>
</Grid>
</Grid>
<Button
className={!this.props.value ? this.props.classes.errorButton : null }
style={{marginTop: '5px', height: '40px'}}
variant='contained'
color='primary'
onClick={() => {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'}
</Button>
</div>
<Button
className={!this.props.value || this.props.error.steps[this.props.index].xml ? this.props.classes.errorButton : null }
style={{marginTop: '5px', height: '40px'}}
variant='contained'
color='primary'
onClick={() => {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'}
</Button>
</div>
)}
: null}
</div>
);
+114 -6
View File
@@ -1,10 +1,11 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { checkError } from '../../../actions/tutorialBuilderActions';
import { checkError, readJSON, 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';
@@ -12,14 +13,30 @@ import Id from './Id';
import Title from './Textfield';
import Step from './Step';
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 Divider from '@material-ui/core/Divider';
const styles = (theme) => ({
backdrop: {
zIndex: theme.zIndex.drawer + 1,
color: '#fff',
}
});
class Builder extends Component {
constructor(props){
super(props);
this.inputRef = React.createRef();
}
submit = () => {
var isError = this.props.checkError();
if(isError){
alert('Error');
window.scrollTo(0, 0);
}
else{
var tutorial = {
@@ -32,6 +49,74 @@ class Builder extends Component {
}
}
reset = () => {
this.props.resetTutorial();
window.scrollTo(0, 0);
}
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.' });
}
else {
var reader = new FileReader();
reader.readAsText(jsonFile);
reader.onloadend = () => {
try {
var result = JSON.parse(reader.result);
if(this.checkSteps(result.steps)){
alert('Hier');
this.props.readJSON(result);
}
else{
this.props.progress(false);
alert('die JSON-Datei hat nicht die richtige Form');
}
} catch(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.' });
}
};
}
}
checkSteps = (steps) => {
if(!(steps && steps.length > 0)){
alert(1);
return false;
}
steps.map((step, i) => {
if(i === 0){
if(!(step.requirements &&
step.requirements.length > 0 &&
step.requirements.filter(requirement => typeof(requirement) === 'number').length === step.requirements.length)){
alert(3);
return false;
}
var hardwareIds = data.map(hardware => hardware.id);
if(!(step.hardware &&
step.hardware.length > 0 &&
step.hardware.filter(hardware => typeof(hardware) === 'string' && hardwareIds.includes(hardware)).length === step.hardware.length)){
alert(4);
return false;
}
}
if(!(step.headline && typeof(step.headline)==='string')){
alert(5);
return false;
}
if(!(step.text && typeof(step.text)==='string')){
alert(6);
return false;
}
});
return true;
}
render() {
return (
@@ -40,6 +125,20 @@ class Builder extends Component {
<h1>Tutorial-Builder</h1>
<div ref={this.inputRef}>
<input
style={{display: 'none'}}
accept="application/json"
onChange={(e) => {this.uploadJsonFile(e.target.files[0])}}
id="open-json"
type="file"
/>
<label htmlFor="open-json">
<Button component="span" style={{marginRight: '10px', marginBottom: '10px'}} variant='contained' color='primary'>Datei laden</Button>
</label>
</div>
<Divider variant='fullWidth' style={{margin: '10px 0 30px 0'}}/>
<Id error={this.props.error} value={this.props.id}/>
<Title value={this.props.title} property={'title'} label={'Titel'} error={this.props.error}/>
@@ -49,7 +148,11 @@ class Builder extends Component {
)}
<Button variant='contained' color='primary' onClick={() => this.submit()}>Tutorial-Vorlage erstellen</Button>
<Button style={{marginRight: '10px'}} variant='contained' color='primary' onClick={() => this.submit()}>Tutorial-Vorlage erstellen</Button>
<Button variant='contained' onClick={() => this.reset()}>Zurücksetzen</Button>
<Backdrop className={this.props.classes.backdrop} open={this.props.isProgress}>
<CircularProgress color="inherit" />
</Backdrop>
</div>
@@ -63,10 +166,14 @@ class Builder extends Component {
Builder.propTypes = {
checkError: PropTypes.func.isRequired,
readJSON: 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
error: PropTypes.object.isRequired,
isProgress: PropTypes.bool.isRequired
};
const mapStateToProps = state => ({
@@ -74,7 +181,8 @@ const mapStateToProps = state => ({
id: state.builder.id,
steps: state.builder.steps,
change: state.builder.change,
error: state.builder.error
error: state.builder.error,
isProgress: state.builder.progress
});
export default connect(mapStateToProps, { checkError })(Builder);
export default connect(mapStateToProps, { checkError, readJSON, progress, resetTutorial })(withStyles(styles, {withTheme: true})(Builder));
+3 -3
View File
@@ -89,11 +89,11 @@ class Step extends Component {
<Textfield value={this.props.step.text} property={'text'} label={this.props.step.type === 'task' ? 'Aufgabenstellung' : 'Instruktionen'} index={index} multiline error={this.props.error} errorText={`Gib Instruktionen für die ${this.props.step.type === 'task' ? 'Aufgabe' : 'Anleitung'} ein.`}/>
{index === 0 ?
<div>
<Requirements value={this.props.step.requirements} index={index}/>
<Hardware value={this.props.step.hardware} index={index} error={this.props.error}/>
<Requirements value={this.props.step.requirements ? this.props.step.requirements : []} index={index}/>
<Hardware value={this.props.step.hardware ? this.props.step.hardware : []} index={index} error={this.props.error}/>
</div>
: null}
<BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} />
<BlocklyExample value={this.props.step.xml} index={index} task={this.props.step.type === 'task'} error={this.props.error}/>
</div>
</div>
</div>
+1 -1
View File
@@ -11,7 +11,7 @@ class StepType extends Component {
render() {
return (
<RadioGroup row value={this.props.value} onChange={(e) => {this.props.changeContent(this.props.index, 'type', e.target.value)}}>
<RadioGroup row value={this.props.value === 'task' ? 'task' : 'instruction'} onChange={(e) => {this.props.changeContent(this.props.index, 'type', e.target.value)}}>
<FormControlLabel style={{color: 'black'}}
value="instruction"
control={<Radio color="primary" />}