From 0cb7bba5212c906add2fcd0bf383f55b71111824 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 16 Oct 2020 14:32:52 +0200 Subject: [PATCH 01/10] add blockly project gallery --- src/components/Gallery/GalleryHome.js | 100 ++++++++++++++++++++++++++ src/components/Gallery/gallery.json | 37 ++++++++++ src/components/Home.js | 21 +++++- src/components/Navbar.js | 44 ++++++------ src/components/Routes.js | 6 +- 5 files changed, 183 insertions(+), 25 deletions(-) create mode 100644 src/components/Gallery/GalleryHome.js create mode 100644 src/components/Gallery/gallery.json diff --git a/src/components/Gallery/GalleryHome.js b/src/components/Gallery/GalleryHome.js new file mode 100644 index 0000000..6c68f34 --- /dev/null +++ b/src/components/Gallery/GalleryHome.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import clsx from 'clsx'; + +import Breadcrumbs from '../Breadcrumbs'; + +import gallery from './gallery.json'; +// import tutorials from '../../data/tutorials.json'; + +import { Link } from 'react-router-dom'; + +import { fade } from '@material-ui/core/styles/colorManipulator'; +import { withStyles } from '@material-ui/core/styles'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import BlocklyWindow from '../Blockly/BlocklyWindow'; +import Divider from '@material-ui/core/Divider'; + + +const styles = (theme) => ({ + outerDiv: { + position: 'absolute', + right: '-30px', + bottom: '-30px', + width: '160px', + height: '160px', + color: fade(theme.palette.secondary.main, 0.6) + }, + outerDivError: { + stroke: fade(theme.palette.error.dark, 0.6), + color: fade(theme.palette.error.dark, 0.6) + }, + outerDivSuccess: { + stroke: fade(theme.palette.primary.main, 0.6), + color: fade(theme.palette.primary.main, 0.6) + }, + outerDivOther: { + stroke: fade(theme.palette.secondary.main, 0.6) + }, + innerDiv: { + width: 'inherit', + height: 'inherit', + display: 'table-cell', + verticalAlign: 'middle', + textAlign: 'center' + } +}); + + +class GalleryHome extends Component { + + render() { + return ( +
+ + +

Gallery

+ + {gallery.map((gallery, i) => { + return ( + + + +

{gallery.title}

+ + +

{gallery.text}

+ +

{gallery.name}

+ +
+
+
+ +
+ ) + })} +
+
+ ); + }; +} + +GalleryHome.propTypes = { + status: PropTypes.array.isRequired, + change: PropTypes.number.isRequired, +}; + +const mapStateToProps = state => ({ + change: state.tutorial.change, + status: state.tutorial.status +}); + +export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(GalleryHome)); diff --git a/src/components/Gallery/gallery.json b/src/components/Gallery/gallery.json new file mode 100644 index 0000000..0ff72ae --- /dev/null +++ b/src/components/Gallery/gallery.json @@ -0,0 +1,37 @@ +[ + { + "id": 15212, + "title": "Das senseBox Buch Kapitel 1", + "name": "Mario", + "text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ", + "xml": "\n \n \n \n 10\n \n \n \n" + }, + { + "id": 25451, + "title": "Das senseBox Buch Kapitel 2", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n 1\n HIGH\n \n \n \n \n 1000\n \n \n \n \n 1\n LOW\n \n \n \n \n 1000\n \n \n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 3541512, + "title": "Das senseBox Buch Kapitel 3", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n \n \n \n \n \n WHITE,BLACK\n \n \n 1\n \n \n \n \n 0\n \n \n \n \n 0\n \n \n \n \n \n \n \n Helligkeit:\n \n \n \n \n Illuminance\n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 7487454, + "title": "Das senseBox Buch Kapitel 4", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n \n \n \n \n \n WHITE,BLACK\n \n \n 1\n \n \n \n \n 0\n \n \n \n \n 0\n \n \n \n \n \n \n \n Helligkeit:\n \n \n \n \n Illuminance\n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 54541251, + "title": "Das senseBox Buch Kapitel 5", + "name": "Mario", + "text": "", + "xml": "" + } +] \ No newline at end of file diff --git a/src/components/Home.js b/src/components/Home.js index 86deb9a..861dbd1 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -18,6 +18,7 @@ import { withStyles } from '@material-ui/core/styles'; import { faCode } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import gallery from './Gallery/gallery.json'; const styles = (theme) => ({ codeOn: { @@ -44,14 +45,21 @@ const styles = (theme) => ({ class Home extends Component { state = { - codeOn: false + codeOn: false, + projectToLoad: undefined } + componentDidMount() { + this.setState({ projectToLoad: gallery.find(project => project.id == this.props.match.params.galleryId) }) + } + + componentDidUpdate() { /* Resize and reposition all of the workspace chrome (toolbox, trash, scrollbars etc.) This should be called when something changes that requires recalculating dimensions and positions of the trash, zoom, toolbox, etc. (e.g. window resize). */ + const workspace = Blockly.getMainWorkspace(); Blockly.svgResize(workspace); } @@ -71,6 +79,12 @@ class Home extends Component { } render() { + // console.log(this.props.match.params.galleryId); + // console.log(gallery); + // console.log(gallery.filter(project => project.id == this.props.match.params.galleryId)); + if (this.state.projectToLoad) { + console.log(this.state.projectToLoad.xml) + } return (
@@ -87,7 +101,10 @@ class Home extends Component { - + {this.state.projectToLoad ? + < BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} /> : < BlocklyWindow blocklyCSS={{ height: '80vH' }} /> + } + {this.state.codeOn ? diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 023981a..a70d9a4 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -45,32 +45,32 @@ class Navbar extends Component { this.setState({ open: !this.state.open }); } - render(){ + render() { return (
- + - + senseBox Blockly - - senseBox-Logo + + senseBox-Logo {/^\/tutorial(\/.*$|$)/g.test(this.props.location.pathname) ? - + Tutorial @@ -82,34 +82,34 @@ class Navbar extends Component { anchor="left" onClose={this.toggleDrawer} open={this.state.open} - classes={{paper: this.props.classes.drawerWidth}} - ModalProps={{keepMounted: true}} // Better open performance on mobile. + classes={{ paper: this.props.classes.drawerWidth }} + ModalProps={{ keepMounted: true }} // Better open performance on mobile. > -
-
- +
+
+ Menü -
+
- {[{text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial"}, {text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder"}, {text: 'Einstellungen', icon: faCog, link: "/settings"}].map((item, index) => ( - + {[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder" }, { text: 'Gallery', icon: faFolderPlus, link: "/gallery" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => ( + - + ))} - + - {[{text: 'Über uns', icon: faBuilding},{text: 'Kontakt', icon: faEnvelope}, {text: 'Impressum', icon: faIdCard}].map((item, index) => ( + {[{ text: 'Über uns', icon: faBuilding }, { text: 'Kontakt', icon: faEnvelope }, { text: 'Impressum', icon: faIdCard }].map((item, index) => ( - + ))} @@ -120,4 +120,4 @@ class Navbar extends Component { } } -export default withStyles(styles, {withTheme: true})(withRouter(Navbar)); +export default withStyles(styles, { withTheme: true })(withRouter(Navbar)); diff --git a/src/components/Routes.js b/src/components/Routes.js index 70153de..2993e7d 100644 --- a/src/components/Routes.js +++ b/src/components/Routes.js @@ -7,6 +7,8 @@ import Tutorial from './Tutorial/Tutorial'; import TutorialHome from './Tutorial/TutorialHome'; import Builder from './Tutorial/Builder/Builder'; import NotFound from './NotFound'; +import GalleryHome from './Gallery/GalleryHome'; + class Routes extends Component { @@ -16,7 +18,9 @@ class Routes extends Component { - + + + From e647d6e58e96870279ed57eea5d7a4b0ded7d973 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 16 Oct 2020 22:33:02 +0200 Subject: [PATCH 02/10] add block sharing --- .env | 1 + package-lock.json | 32 ++++- package.json | 4 +- src/components/Gallery/GalleryHome.js | 20 ++- src/components/Home.js | 13 +- src/components/Routes.js | 1 + src/components/WorkspaceFunc.js | 177 +++++++++++++++++++------- 7 files changed, 194 insertions(+), 54 deletions(-) diff --git a/.env b/.env index 8a24119..a563d82 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ REACT_APP_COMPILER_URL=https://compiler.sensebox.de REACT_APP_BOARD=sensebox-mcu +REACT_APP_BLOCKLY_API=http://46.101.243.134:3000 diff --git a/package-lock.json b/package-lock.json index 6a8dc6d..50dcf2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8720,6 +8720,11 @@ "minimist": "^1.2.5" } }, + "mnemonic-id": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mnemonic-id/-/mnemonic-id-3.2.7.tgz", + "integrity": "sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA==" + }, "moment": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz", @@ -11394,6 +11399,13 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "request-promise-core": { @@ -12125,6 +12137,13 @@ "requires": { "faye-websocket": "^0.10.0", "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "sockjs-client": { @@ -13269,9 +13288,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "v8-compile-cache": { "version": "2.1.1", @@ -13929,6 +13948,13 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "webpack-manifest-plugin": { diff --git a/package.json b/package.json index a7a911e..67df513 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@testing-library/user-event": "^7.2.1", "blockly": "^3.20200924.0", "file-saver": "^2.0.2", + "mnemonic-id": "^3.2.7", "moment": "^2.28.0", "prismjs": "^1.20.0", "react": "^16.13.1", @@ -23,7 +24,8 @@ "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "redux": "^4.0.5", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "uuid": "^8.3.1" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/Gallery/GalleryHome.js b/src/components/Gallery/GalleryHome.js index 6c68f34..4a1a83c 100644 --- a/src/components/Gallery/GalleryHome.js +++ b/src/components/Gallery/GalleryHome.js @@ -6,7 +6,7 @@ import clsx from 'clsx'; import Breadcrumbs from '../Breadcrumbs'; -import gallery from './gallery.json'; +// import gallery from './gallery.json'; // import tutorials from '../../data/tutorials.json'; import { Link } from 'react-router-dom'; @@ -49,8 +49,24 @@ const styles = (theme) => ({ }); + + class GalleryHome extends Component { + state = { + gallery: [] + } + + componentDidMount() { + console.log(process.env.REACT_APP_BLOCKLY_API) + fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname) + .then(res => res.json()) + .then((data) => { + this.setState({ gallery: data }) + }) + } + + render() { return (
@@ -58,7 +74,7 @@ class GalleryHome extends Component {

Gallery

- {gallery.map((gallery, i) => { + {this.state.gallery.map((gallery, i) => { return ( diff --git a/src/components/Home.js b/src/components/Home.js index 861dbd1..3b8ed31 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -10,6 +10,7 @@ import WorkspaceFunc from './WorkspaceFunc'; import BlocklyWindow from './Blockly/BlocklyWindow'; import CodeViewer from './CodeViewer'; import TrashcanButtons from './TrashcanButtons'; +import { createNameId } from 'mnemonic-id'; import Grid from '@material-ui/core/Grid'; import IconButton from '@material-ui/core/IconButton'; @@ -18,7 +19,6 @@ import { withStyles } from '@material-ui/core/styles'; import { faCode } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import gallery from './Gallery/gallery.json'; const styles = (theme) => ({ codeOn: { @@ -46,11 +46,19 @@ class Home extends Component { state = { codeOn: false, + gallery: [], + share: [], projectToLoad: undefined } componentDidMount() { - this.setState({ projectToLoad: gallery.find(project => project.id == this.props.match.params.galleryId) }) + + this.props.workspaceName(createNameId()); + fetch(process.env.BLOCKLY_API + this.props.location.pathname) + .then(res => res.json()) + .then((data) => { + this.setState({ projectToLoad: data }) + }) } @@ -85,6 +93,7 @@ class Home extends Component { if (this.state.projectToLoad) { console.log(this.state.projectToLoad.xml) } + console.log(this.props); return (
diff --git a/src/components/Routes.js b/src/components/Routes.js index 2993e7d..f312005 100644 --- a/src/components/Routes.js +++ b/src/components/Routes.js @@ -20,6 +20,7 @@ class Routes extends Component { + diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js index 0b74f0c..7626bca 100644 --- a/src/components/WorkspaceFunc.js +++ b/src/components/WorkspaceFunc.js @@ -12,7 +12,6 @@ import { initialXml } from './Blockly/initialXml.js'; import Compile from './Compile'; import SolutionCheck from './Tutorial/SolutionCheck'; -import Dialog from './Dialog'; import Snackbar from './Snackbar'; import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; @@ -22,8 +21,19 @@ import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; +import { createId } from 'mnemonic-id'; -import { faPen, faSave, faUpload, faCamera, faShare } from "@fortawesome/free-solid-svg-icons"; + +import Dialog from './Dialog'; +// import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; + + + +import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; const styles = (theme) => ({ @@ -49,9 +59,10 @@ const styles = (theme) => ({ }); + class WorkspaceFunc extends Component { - constructor(props){ + constructor(props) { super(props); this.inputRef = React.createRef(); this.state = { @@ -60,21 +71,25 @@ class WorkspaceFunc extends Component { open: false, file: false, saveFile: false, + share: false, name: props.name, snackbar: false, key: '', - message: '' + message: '', + id: '' }; } - componentDidUpdate(props){ - if(props.name !== this.props.name){ - this.setState({name: this.props.name}); + + + componentDidUpdate(props) { + if (props.name !== this.props.name) { + this.setState({ name: this.props.name }); } } toggleDialog = () => { - this.setState({ open: !this.state }); + this.setState({ open: !this.state, share: false }); } saveXmlFile = () => { @@ -87,6 +102,41 @@ class WorkspaceFunc extends Component { saveAs(blob, fileName); } + shareBlocks = () => { + let code = this.props.xml; + let requestOptions = ''; + let id = ''; + if (this.state.id !== '') { + requestOptions = { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + id: this.state.id, + name: this.state.name, + xml: code + }) + }; + fetch(process.env.BLOCKLY_API + '/share' + this.state.id, requestOptions) + .then(response => response.json()) + .then(data => this.setState({ share: true })); + } + else { + id = createId(10); + requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + id: id, + name: this.state.name, + xml: code + }) + }; + fetch(process.env.BLOCKLY_API + '/share', requestOptions) + .then(response => response.json()) + .then(data => this.setState({ id: data.id, share: true })); + } + } + getSvg = () => { const workspace = Blockly.getMainWorkspace(); var canvas = workspace.svgBlockCanvas_.cloneNode(true); @@ -98,7 +148,7 @@ class WorkspaceFunc extends Component { // var cssContent = Blockly.Css.CONTENT.join(''); var cssContent = ''; for (var i = 0; i < document.getElementsByTagName('style').length; i++) { - if(/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)){ + if (/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)) { cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.'); } } @@ -125,22 +175,22 @@ class WorkspaceFunc extends Component { } createFileName = (filetype) => { - this.setState({file: filetype}, () => { - if(this.state.name){ + this.setState({ file: filetype }, () => { + if (this.state.name) { this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() } - else{ + else { this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Blöcke speichern' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf 'Eingabe'.` }); } }); } setFileName = (e) => { - this.setState({name: e.target.value}); + this.setState({ name: e.target.value }); } uploadXmlFile = (xmlFile) => { - if(xmlFile.type !== 'text/xml'){ + if (xmlFile.type !== 'text/xml') { this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur XML-Dateien zulässig.' }); } else { @@ -155,18 +205,18 @@ class WorkspaceFunc extends Component { workspace.clear(); this.props.clearStats(); Blockly.Xml.domToWorkspace(xmlDom, workspace); - if(workspace.getAllBlocks().length < 1){ + if (workspace.getAllBlocks().length < 1) { Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xmlBefore), workspace) this.setState({ open: true, file: false, title: 'Keine Blöcke', content: 'Es wurden keine Blöcke detektiert. Bitte überprüfe den XML-Code und versuche es erneut.' }); } else { - if(!this.props.solutionCheck){ + if (!this.props.solutionCheck) { var extensionPosition = xmlFile.name.lastIndexOf('.'); this.props.workspaceName(xmlFile.name.substr(0, extensionPosition)); } this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' }); } - } catch(err){ + } catch (err) { 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.' }); } }; @@ -189,56 +239,60 @@ class WorkspaceFunc extends Component { workspace.options.maxBlocks = Infinity; this.props.onChangeCode(); this.props.clearStats(); - if(!this.props.solutionCheck){ + if (!this.props.solutionCheck) { this.props.workspaceName(null); } this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' }); } + + render() { return ( -
+
{!this.props.solutionCheck ? - -
{this.setState({file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.'})}}> - {this.props.name && !isWidthDown('xs', this.props.width) ? {this.props.name} : null} -
- + +
{ this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}> + {this.props.name && !isWidthDown('xs', this.props.width) ? {this.props.name} : null} +
+ +
-
- : null} + : null} {this.props.solutionCheck ? : } - + {this.createFileName('xml');}} + onClick={() => { this.createFileName('xml'); }} > - + -
+
{this.uploadXmlFile(e.target.files[0])}} + onChange={(e) => { this.uploadXmlFile(e.target.files[0]) }} id="open-blocks" type="file" />