├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── gulpfile.js ├── images ├── electron_sequence.png ├── screen1.png ├── screen2.png ├── screen3.png └── screen4.png ├── main.js ├── package-lock.json ├── package.json ├── reactron.ini ├── sample_rest ├── README.md ├── index.js ├── package-lock.json └── package.json └── src ├── app.js ├── app.test.js ├── components ├── app-about.js ├── app-bar.js ├── app-button.js ├── app-menu.js ├── basic-form.js ├── command.js ├── fs_inifile.js ├── rest.js └── welcome.js ├── index.css ├── index.html └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", "@babel/react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | # Build Folders 4 | app/ 5 | dist/ 6 | 7 | # MacOS Finder 8 | .DS_Store 9 | 10 | # WebStorm Project Folder 11 | .idea 12 | 13 | # Jest Snapshot Folder 14 | **/__snapshots__/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reactron 2 | 3 | Reactron is a simple project that integrates [React.js](https://reactjs.org/), [Electron](https://electronjs.org/) and [Material Design](https://material-ui.com/pt/) as interface. 4 | 5 | ## Project Features 6 | 7 | + Routing 8 | + Execution of OS commands with return of information (stdout) 9 | + Construction of custom components 10 | + Menus, Dialogs and other Material UI components 11 | + Rest consume 12 | + Basic form 13 | + IO on disk (INI files) 14 | 15 | ## Installing 16 | 17 | You will need [NPM](https://nodejs.org/en/) installed. 18 | Follow the commands below: 19 | 20 | ```bash 21 | # Clone repository 22 | git clone https://github.com/ricardomansano/reactron.git reactron 23 | 24 | # Go to directory 25 | cd reactron 26 | 27 | # Install dependencies 28 | npm install 29 | ``` 30 | 31 | ## Run the project from the command 32 | 33 | ```bash 34 | npm start 35 | [or] 36 | npm run start 37 | ``` 38 | 39 | ## Compiling for distribution 40 | 41 | ```bash 42 | npm run dist 43 | ``` 44 | 45 | The application will be generated in the `dist` folder of your project. 46 | 47 | ## How Reactron works with React 48 | 49 | The template compiles the `*.js` (jsx) files contained in the `src` folder into standard JavaScript files into the `app` folder, including also the `*.html` and `*.css` files, along with the `file main.js`. 50 | 51 | It then packages the application using `gulp` through `npm`. 52 | 53 | 54 |

55 | electron_sequence 56 |

57 | 58 | ## Screenshot 59 | 60 |

61 | electron_sequence 62 |

63 |

64 | electron_sequence 65 |

66 |

67 | electron_sequence 68 |

69 |

70 | electron_sequence 71 |

72 | 73 | ## Important tip 74 | Do not use **folders with spaces** in the name. 75 | 76 | EX: c://dir/reactron 77 | 78 | ## License 79 | 80 | This project is under the license [MIT](https://www.opensource.org/licenses/mit-license.php) 81 | 82 | Based on the project [Electrate](https://github.com/mmick66/electrate) (under license: [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.pt_BR)) 83 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const exec = require('child_process').exec; 2 | 3 | const gulp = require('gulp'); 4 | const babel = require('gulp-babel'); 5 | const css = require('gulp-clean-css'); 6 | const livereload = require('gulp-livereload'); 7 | 8 | gulp.task('copy', () => { 9 | return gulp.src('assets/**/*') 10 | .pipe(gulp.dest('app/assets')); 11 | }); 12 | 13 | gulp.task('html', () => { 14 | return gulp.src('src/index.html') 15 | .pipe(gulp.dest('app/')) 16 | .pipe(livereload()); 17 | }); 18 | 19 | gulp.task('css', () => { 20 | return gulp.src('src/**/*.css') 21 | .pipe(css()) 22 | .pipe(gulp.dest('app/')) 23 | .pipe(livereload()); 24 | }); 25 | 26 | gulp.task('js', () => { 27 | return gulp.src(['main.js', 'src/**/*.js']) 28 | .pipe(babel()) 29 | .pipe(gulp.dest('app/')) 30 | .pipe(livereload()); 31 | }); 32 | 33 | gulp.task('watch', async function () { 34 | livereload.listen(); 35 | gulp.watch('src/**/*.html', gulp.series('html')); 36 | gulp.watch('src/**/*.css', gulp.series('css')); 37 | gulp.watch('src/**/*.js', gulp.series('js')); 38 | }); 39 | 40 | gulp.task('build', gulp.series('copy', 'html', 'css', 'js')); 41 | 42 | gulp.task('start', gulp.series('build', () => { 43 | return exec( 44 | __dirname + '/node_modules/.bin/electron .' 45 | ).on('close', () => process.exit()); 46 | })); 47 | 48 | gulp.task('default', gulp.parallel('start', 'watch')); 49 | 50 | gulp.task('dist', gulp.series('build', () => { 51 | return exec( 52 | __dirname + '/node_modules/.bin/electron-builder .' 53 | ).on('close', () => process.exit()); 54 | })); 55 | -------------------------------------------------------------------------------- /images/electron_sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardomansano/reactron/5eb84e3f00fc5c88223d4305b26d3888a9cd9b7f/images/electron_sequence.png -------------------------------------------------------------------------------- /images/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardomansano/reactron/5eb84e3f00fc5c88223d4305b26d3888a9cd9b7f/images/screen1.png -------------------------------------------------------------------------------- /images/screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardomansano/reactron/5eb84e3f00fc5c88223d4305b26d3888a9cd9b7f/images/screen2.png -------------------------------------------------------------------------------- /images/screen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardomansano/reactron/5eb84e3f00fc5c88223d4305b26d3888a9cd9b7f/images/screen3.png -------------------------------------------------------------------------------- /images/screen4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricardomansano/reactron/5eb84e3f00fc5c88223d4305b26d3888a9cd9b7f/images/screen4.png -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow } = require('electron') 2 | const url = require('url') 3 | const path = require('path') 4 | 5 | let mainWindow 6 | 7 | // Functions must be exported to be accessible to the front-end 8 | // Execute OS command and return result to front-end 9 | // Another process is the IPCMaine IPCRenderer 10 | // https://electronjs.org/docs/api/ipc-main 11 | // https://electronjs.org/docs/api/ipc-renderer 12 | exports.execProcess = (process, callback) => { 13 | const { exec } = require('child_process') 14 | const callExec = exec(process) 15 | 16 | callExec.stdout.on('data', function (data) { 17 | callback(data) 18 | }) 19 | callExec.stderr.on('data', function (data) { 20 | callback("ERROR: \n" + data) 21 | }) 22 | } 23 | 24 | const createWindow = () => { 25 | mainWindow = new BrowserWindow({ 26 | width: 800, 27 | height: 600, 28 | 29 | // Window's Visual Features 30 | frame: false, // Remove top bar 31 | useContentSize: false, // Inhibit window size display 32 | 33 | webPreferences: { 34 | nodeIntegration: true 35 | } 36 | }); 37 | 38 | mainWindow.loadURL(url.format({ 39 | pathname: path.join(__dirname, 'index.html'), 40 | protocol: 'file:', 41 | slashes: true 42 | })); 43 | 44 | mainWindow.on('closed', () => { 45 | mainWindow = null 46 | }); 47 | }; 48 | 49 | app.whenReady() 50 | .then(createWindow) 51 | 52 | app.on('window-all-closed', () => { 53 | if (process.platform !== 'darwin') { 54 | app.quit() 55 | } 56 | }); 57 | 58 | app.on('activate', () => { 59 | if (BrowserWindow.getAllWindows().length === 0) { 60 | createWindow() 61 | } 62 | }); 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactron", 3 | "displayName": "Projeto base para uma aplicacao React/Electron/Material", 4 | "description": "Projeto base para uma aplicacao React/Electron/Material", 5 | "version": "1.1.0", 6 | "license": "MIT", 7 | "repository": "https://github.com/ricardomansano/reactron", 8 | "publisher": "Mansano", 9 | "author": { 10 | "name": "Ricardo Mansano", 11 | "email": "ricardomansano@live.com" 12 | }, 13 | "main": "app/main.js", 14 | "scripts": { 15 | "postinstall": "install-app-deps", 16 | "build": "gulp build", 17 | "start": "gulp", 18 | "dist": "gulp dist" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.6.0", 22 | "@babel/plugin-proposal-class-properties": "^7.5.5", 23 | "@babel/preset-env": "^7.6.0", 24 | "@babel/preset-react": "^7.0.0", 25 | "babel-jest": "^24.8.0", 26 | "electron": "5.0.10", 27 | "electron-builder": "^20.39.0", 28 | "electron-react-devtools": "^0.5.3", 29 | "gulp": "^4.0.2", 30 | "gulp-babel": "^8.0.0", 31 | "gulp-clean-css": "^4.2.0", 32 | "gulp-concat": "^2.6.1", 33 | "gulp-livereload": "^4.0.1", 34 | "jest": "^24.8.0", 35 | "react-test-renderer": "^16.8.6" 36 | }, 37 | "dependencies": { 38 | "@material-ui/core": "^4.4.0", 39 | "@material-ui/icons": "^4.2.1", 40 | "@material-ui/styles": "^4.3.3", 41 | "@types/material-ui": "^0.21.7", 42 | "electron-is-dev": "^1.1.0", 43 | "ini": "^1.3.5", 44 | "material-ui": "^0.20.2", 45 | "react": "^16.8.6", 46 | "react-dom": "^16.8.6", 47 | "react-router-dom": "^5.0.1" 48 | }, 49 | "build": { 50 | "appId": "com.ricardomansano.rectron", 51 | "linux": { 52 | "target": [ 53 | "dir" 54 | ] 55 | }, 56 | "win": { 57 | "target": [ 58 | { 59 | "target": "dir", 60 | "arch": [ 61 | "x64", 62 | "ia32" 63 | ] 64 | } 65 | ] 66 | }, 67 | "mac": { 68 | "category": "your.app.category.type" 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /reactron.ini: -------------------------------------------------------------------------------- 1 | Escopo="Scope variable " 2 | 3 | [files] 4 | file1=file1.png 5 | file3=file3.png 6 | -------------------------------------------------------------------------------- /sample_rest/README.md: -------------------------------------------------------------------------------- 1 | Para utilizar o sample_rest execute: 2 | 3 | npm install 4 | node index.js 5 | -------------------------------------------------------------------------------- /sample_rest/index.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var app = express() 3 | let port = 3333 4 | 5 | app.listen(port, () => { 6 | console.log(`Server running on port: ${port}`); 7 | }); 8 | 9 | app.get("/url", (req, res, next) => { 10 | // Return query parameters to response 11 | console.log(req.query) 12 | res.json(req.query) 13 | }); -------------------------------------------------------------------------------- /sample_rest/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample_rest", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.8", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 10 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 11 | "requires": { 12 | "mime-types": "~2.1.34", 13 | "negotiator": "0.6.3" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 20 | }, 21 | "body-parser": { 22 | "version": "1.19.2", 23 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", 24 | "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", 25 | "requires": { 26 | "bytes": "3.1.2", 27 | "content-type": "~1.0.4", 28 | "debug": "2.6.9", 29 | "depd": "~1.1.2", 30 | "http-errors": "1.8.1", 31 | "iconv-lite": "0.4.24", 32 | "on-finished": "~2.3.0", 33 | "qs": "6.9.7", 34 | "raw-body": "2.4.3", 35 | "type-is": "~1.6.18" 36 | } 37 | }, 38 | "bytes": { 39 | "version": "3.1.2", 40 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 41 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 42 | }, 43 | "content-disposition": { 44 | "version": "0.5.4", 45 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 46 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 47 | "requires": { 48 | "safe-buffer": "5.2.1" 49 | } 50 | }, 51 | "content-type": { 52 | "version": "1.0.4", 53 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 54 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 55 | }, 56 | "cookie": { 57 | "version": "0.4.2", 58 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", 59 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" 60 | }, 61 | "cookie-signature": { 62 | "version": "1.0.6", 63 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 64 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 65 | }, 66 | "debug": { 67 | "version": "2.6.9", 68 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 69 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 70 | "requires": { 71 | "ms": "2.0.0" 72 | } 73 | }, 74 | "depd": { 75 | "version": "1.1.2", 76 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 77 | "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" 78 | }, 79 | "destroy": { 80 | "version": "1.0.4", 81 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 82 | "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" 83 | }, 84 | "ee-first": { 85 | "version": "1.1.1", 86 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 87 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 88 | }, 89 | "encodeurl": { 90 | "version": "1.0.2", 91 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 92 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 93 | }, 94 | "escape-html": { 95 | "version": "1.0.3", 96 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 97 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 98 | }, 99 | "etag": { 100 | "version": "1.8.1", 101 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 102 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 103 | }, 104 | "express": { 105 | "version": "4.17.3", 106 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", 107 | "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", 108 | "requires": { 109 | "accepts": "~1.3.8", 110 | "array-flatten": "1.1.1", 111 | "body-parser": "1.19.2", 112 | "content-disposition": "0.5.4", 113 | "content-type": "~1.0.4", 114 | "cookie": "0.4.2", 115 | "cookie-signature": "1.0.6", 116 | "debug": "2.6.9", 117 | "depd": "~1.1.2", 118 | "encodeurl": "~1.0.2", 119 | "escape-html": "~1.0.3", 120 | "etag": "~1.8.1", 121 | "finalhandler": "~1.1.2", 122 | "fresh": "0.5.2", 123 | "merge-descriptors": "1.0.1", 124 | "methods": "~1.1.2", 125 | "on-finished": "~2.3.0", 126 | "parseurl": "~1.3.3", 127 | "path-to-regexp": "0.1.7", 128 | "proxy-addr": "~2.0.7", 129 | "qs": "6.9.7", 130 | "range-parser": "~1.2.1", 131 | "safe-buffer": "5.2.1", 132 | "send": "0.17.2", 133 | "serve-static": "1.14.2", 134 | "setprototypeof": "1.2.0", 135 | "statuses": "~1.5.0", 136 | "type-is": "~1.6.18", 137 | "utils-merge": "1.0.1", 138 | "vary": "~1.1.2" 139 | } 140 | }, 141 | "finalhandler": { 142 | "version": "1.1.2", 143 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 144 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 145 | "requires": { 146 | "debug": "2.6.9", 147 | "encodeurl": "~1.0.2", 148 | "escape-html": "~1.0.3", 149 | "on-finished": "~2.3.0", 150 | "parseurl": "~1.3.3", 151 | "statuses": "~1.5.0", 152 | "unpipe": "~1.0.0" 153 | } 154 | }, 155 | "forwarded": { 156 | "version": "0.2.0", 157 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 158 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 159 | }, 160 | "fresh": { 161 | "version": "0.5.2", 162 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 163 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 164 | }, 165 | "http-errors": { 166 | "version": "1.8.1", 167 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", 168 | "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", 169 | "requires": { 170 | "depd": "~1.1.2", 171 | "inherits": "2.0.4", 172 | "setprototypeof": "1.2.0", 173 | "statuses": ">= 1.5.0 < 2", 174 | "toidentifier": "1.0.1" 175 | } 176 | }, 177 | "iconv-lite": { 178 | "version": "0.4.24", 179 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 180 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 181 | "requires": { 182 | "safer-buffer": ">= 2.1.2 < 3" 183 | } 184 | }, 185 | "inherits": { 186 | "version": "2.0.4", 187 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 188 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 189 | }, 190 | "ipaddr.js": { 191 | "version": "1.9.1", 192 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 193 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 194 | }, 195 | "media-typer": { 196 | "version": "0.3.0", 197 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 198 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 199 | }, 200 | "merge-descriptors": { 201 | "version": "1.0.1", 202 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 203 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 204 | }, 205 | "methods": { 206 | "version": "1.1.2", 207 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 208 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 209 | }, 210 | "mime": { 211 | "version": "1.6.0", 212 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 213 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 214 | }, 215 | "mime-db": { 216 | "version": "1.52.0", 217 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 218 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 219 | }, 220 | "mime-types": { 221 | "version": "2.1.35", 222 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 223 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 224 | "requires": { 225 | "mime-db": "1.52.0" 226 | } 227 | }, 228 | "ms": { 229 | "version": "2.0.0", 230 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 231 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 232 | }, 233 | "negotiator": { 234 | "version": "0.6.3", 235 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 236 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 237 | }, 238 | "on-finished": { 239 | "version": "2.3.0", 240 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 241 | "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", 242 | "requires": { 243 | "ee-first": "1.1.1" 244 | } 245 | }, 246 | "parseurl": { 247 | "version": "1.3.3", 248 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 249 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 250 | }, 251 | "path-to-regexp": { 252 | "version": "0.1.7", 253 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 254 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 255 | }, 256 | "proxy-addr": { 257 | "version": "2.0.7", 258 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 259 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 260 | "requires": { 261 | "forwarded": "0.2.0", 262 | "ipaddr.js": "1.9.1" 263 | } 264 | }, 265 | "qs": { 266 | "version": "6.9.7", 267 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", 268 | "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" 269 | }, 270 | "range-parser": { 271 | "version": "1.2.1", 272 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 273 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 274 | }, 275 | "raw-body": { 276 | "version": "2.4.3", 277 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", 278 | "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", 279 | "requires": { 280 | "bytes": "3.1.2", 281 | "http-errors": "1.8.1", 282 | "iconv-lite": "0.4.24", 283 | "unpipe": "1.0.0" 284 | } 285 | }, 286 | "safe-buffer": { 287 | "version": "5.2.1", 288 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 289 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 290 | }, 291 | "safer-buffer": { 292 | "version": "2.1.2", 293 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 294 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 295 | }, 296 | "send": { 297 | "version": "0.17.2", 298 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", 299 | "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", 300 | "requires": { 301 | "debug": "2.6.9", 302 | "depd": "~1.1.2", 303 | "destroy": "~1.0.4", 304 | "encodeurl": "~1.0.2", 305 | "escape-html": "~1.0.3", 306 | "etag": "~1.8.1", 307 | "fresh": "0.5.2", 308 | "http-errors": "1.8.1", 309 | "mime": "1.6.0", 310 | "ms": "2.1.3", 311 | "on-finished": "~2.3.0", 312 | "range-parser": "~1.2.1", 313 | "statuses": "~1.5.0" 314 | }, 315 | "dependencies": { 316 | "ms": { 317 | "version": "2.1.3", 318 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 319 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 320 | } 321 | } 322 | }, 323 | "serve-static": { 324 | "version": "1.14.2", 325 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", 326 | "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", 327 | "requires": { 328 | "encodeurl": "~1.0.2", 329 | "escape-html": "~1.0.3", 330 | "parseurl": "~1.3.3", 331 | "send": "0.17.2" 332 | } 333 | }, 334 | "setprototypeof": { 335 | "version": "1.2.0", 336 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 337 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 338 | }, 339 | "statuses": { 340 | "version": "1.5.0", 341 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 342 | "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" 343 | }, 344 | "toidentifier": { 345 | "version": "1.0.1", 346 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 347 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 348 | }, 349 | "type-is": { 350 | "version": "1.6.18", 351 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 352 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 353 | "requires": { 354 | "media-typer": "0.3.0", 355 | "mime-types": "~2.1.24" 356 | } 357 | }, 358 | "unpipe": { 359 | "version": "1.0.0", 360 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 361 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 362 | }, 363 | "utils-merge": { 364 | "version": "1.0.1", 365 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 366 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 367 | }, 368 | "vary": { 369 | "version": "1.1.2", 370 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 371 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 372 | } 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /sample_rest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample_rest", 3 | "version": "1.0.0", 4 | "description": "simple rest for test on Reactron", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Mansano", 10 | "license": "MIT", 11 | "dependencies": { 12 | "express": "^4.17.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter as Router, Route } from 'react-router-dom' 3 | import Dialog from '@material-ui/core/Dialog'; 4 | import DialogTitle from '@material-ui/core/DialogTitle'; 5 | import DialogContent from '@material-ui/core/DialogContent'; 6 | import AppBar from './components/app-bar'; 7 | import Welcome from './components/welcome'; 8 | 9 | export default class App extends React.Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = { 13 | pageRouted: Welcome 14 | }; 15 | } 16 | 17 | routePage = (page) => { 18 | this.setState({ pageRouted: page }) 19 | } 20 | 21 | render() { 22 | return ( 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import App from './app'; 3 | import renderer from 'react-test-renderer'; 4 | 5 | test('App is working', () => { 6 | const component = renderer.create(); 7 | let tree = component.toJSON(); 8 | expect(tree).toMatchSnapshot(); 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /src/components/app-about.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | const { shell } = require('electron') 3 | 4 | export default function AppAbout(props) { 5 | const appName = require('../../package.json').name 6 | const appDescription = require('../../package.json').description 7 | const appVersion = require('../../package.json').version 8 | const appLicense = require('../../package.json').license 9 | const appDepends = require('../../package.json').dependencies 10 | 11 | function showDepends() { 12 | let depends = JSON.stringify(appDepends) 13 | depends = depends.substr(1, depends.length - 2) 14 | return depends.replace(/\,/g, "\n") 15 | } 16 | 17 | function openLink(link) { 18 | shell.openExternal(link) 19 | } 20 | 21 | return ( 22 |
23 |

source: app-about.js

24 |

About

25 | Developed by Ricardo Mansano.

26 | Name: {appName} - {appDescription}
27 | Version: {appVersion}
28 | License: {appLicense}

29 | Project dependencies:
30 |
31 |         {showDepends()}
32 |       
33 |
34 | ); 35 | } -------------------------------------------------------------------------------- /src/components/app-bar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import IconButton from '@material-ui/core/IconButton'; 3 | import Close from '@material-ui/icons/Close'; 4 | import Minimize from '@material-ui/icons/Minimize'; 5 | import CropSquare from '@material-ui/icons/CropSquare'; 6 | import FilterNone from '@material-ui/icons/FilterNone'; 7 | 8 | import AppMenu from './app-menu'; 9 | 10 | // Capture Electron Main Window 11 | const { remote } = require('electron') 12 | var window = remote.getCurrentWindow() 13 | 14 | export default class AppBar extends React.Component { 15 | constructor(props) { 16 | super(props) 17 | 18 | this.state = { 19 | maximizeIcon: , 20 | mainApp: props.mainApp 21 | } 22 | } 23 | 24 | // Click event on the [Maximize] button 25 | maximizeButton = () => { 26 | if (window.isMaximized()) 27 | window.restore() 28 | else 29 | window.maximize() 30 | } 31 | 32 | componentDidMount = () => { 33 | // Main window resize event 34 | // I control here the change of the [Maximize] icon 35 | window.addListener("resize", () => { 36 | if (window.isMaximized()) 37 | this.setState({ maximizeIcon: }) 38 | else 39 | this.setState({ maximizeIcon: }) 40 | }) 41 | } 42 | 43 | render() { 44 | // Styles 45 | const appBarStyle = { 46 | WebkitAppRegion: "drag", 47 | zIndex: 1000, 48 | maxHeight: 20, 49 | padding: 6, 50 | paddingTop: 10, 51 | paddingBottom: 10, 52 | height: 100, 53 | color: "#f5f5f5", 54 | backgroundColor: "#494440", 55 | display: "flex", 56 | alignItems: "center", 57 | userSelect: "none", 58 | } 59 | const appButton = { 60 | WebkitAppRegion: "no-drag" 61 | } 62 | const appH1 = { 63 | flexGrow: 1, 64 | margin: 0, 65 | marginLeft: 6, 66 | fontSize: 20 67 | } 68 | 69 | return ( 70 |
71 | 72 |

Reactron

73 | 74 | { window.minimize() }}> 76 | 77 | 78 | { this.maximizeButton() }}> 80 | {this.state.maximizeIcon} 81 | 82 | { window.close() }}> 84 | 85 | 86 |
87 | ) 88 | } 89 | } -------------------------------------------------------------------------------- /src/components/app-button.js: -------------------------------------------------------------------------------- 1 | import Button from '@material-ui/core/Button'; 2 | import { withStyles } from '@material-ui/core/styles'; 3 | 4 | let bgColor = "#D9D9D9" 5 | let bgHoverColor = "#B4B4B4" 6 | const AppButton = withStyles((theme) => ({ 7 | root: { 8 | height: 40, 9 | color: theme.palette.getContrastText(bgColor), 10 | backgroundColor: bgColor, 11 | '&:hover': { 12 | color: theme.palette.getContrastText(bgHoverColor), 13 | backgroundColor: bgHoverColor 14 | }, 15 | }, 16 | }))(Button); 17 | 18 | export default AppButton; -------------------------------------------------------------------------------- /src/components/app-menu.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import IconButton from '@material-ui/core/IconButton'; 3 | import Tooltip from '@material-ui/core/Tooltip'; 4 | import Menu from '@material-ui/core/Menu'; 5 | import MenuItem from '@material-ui/core/MenuItem'; 6 | import Divider from '@material-ui/core/Divider'; 7 | 8 | import MenuButton from '@material-ui/icons/Menu'; 9 | import Welcome from './welcome'; 10 | import BasicForm from './basic-form'; 11 | import Command from './command'; 12 | import AppAbout from './app-about'; 13 | import Rest from './rest' 14 | import FS_Inifile from './fs_inifile' 15 | 16 | export default function AppMenu(props) { 17 | const [anchorEl, setAnchorEl] = React.useState(null); 18 | 19 | function handleClick(event) { 20 | setAnchorEl(event.currentTarget); 21 | } 22 | 23 | function handleClose() { 24 | setAnchorEl(null); 25 | } 26 | 27 | function handleClickOpt(page) { 28 | props.mainApp.routePage(page) 29 | handleClose() 30 | } 31 | 32 | const appButton = { 33 | WebkitAppRegion: "no-drag" 34 | } 35 | 36 | return ( 37 |
38 | 39 | 42 | 43 | 44 | 45 | 46 | 53 | { handleClickOpt(Welcome) }}>Welcome 54 | { handleClickOpt(BasicForm) }}>Form 55 | { handleClickOpt(Command) }}>Execute Command 56 | { handleClickOpt(Rest) }}>Consume Rest 57 | { handleClickOpt(FS_Inifile) }}>File System / Ini File 58 | 59 | { handleClickOpt(AppAbout) }}>About... 60 | 61 |
62 | ); 63 | } -------------------------------------------------------------------------------- /src/components/basic-form.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextField from '@material-ui/core/TextField'; 3 | import IconButton from '@material-ui/core/IconButton'; 4 | import DeleteForever from '@material-ui/icons/DeleteForever'; 5 | 6 | import AppButton from './app-button' 7 | 8 | export default class BasicForm extends React.Component { 9 | constructor(props) { 10 | super(props) 11 | 12 | this.state = { 13 | data: Array(), 14 | f1: '', 15 | f2: '' 16 | } 17 | } 18 | 19 | onClickSubmit = (e) => { 20 | this.state.data.push({ list: [this.state.f1, this.state.f2] }) 21 | this.setState({ f1: '', f2: '' }) 22 | f1.focus() 23 | e.preventDefault() 24 | } 25 | 26 | onTextChange = (e) => { 27 | // SetState with dynamic name 28 | const { id, value } = e.target 29 | this.setState({ [id]: value }) 30 | } 31 | 32 | delItem = (key) => { 33 | this.state.data.splice(key, 1) 34 | this.setState({ f1: '', f2: '' }); 35 | } 36 | 37 | render() { 38 | return ( 39 |
40 |

source: basic-form.js

41 |

Simple form with interaction between components.

42 | 43 |
{ this.onClickSubmit(event) }}> 44 | { this.onTextChange(event) }} 47 | /> 48 | {" "} 49 | { this.onTextChange(event) }} 52 | /> 53 | {" "} 54 | 55 | 56 | Add 57 | 58 | 59 | 60 | {this.state.data.map((data, index) => { 61 | return 69 | }) 70 | } 71 |
72 | ) 73 | } 74 | } 75 | 76 | // Important: Only one default export allowed per module. 77 | class BasicItem extends React.Component { 78 | constructor(props) { 79 | super(props) 80 | 81 | this.state = { 82 | index: props.index 83 | } 84 | } 85 | 86 | render() { 87 | return ( 88 |
95 | 96 | 98 | 99 | 100 | 101 | | {this.props.f2} | {this.props.f1} 102 |
103 | ); 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/components/command.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextField from '@material-ui/core/TextField'; 3 | 4 | import AppButton from './app-button' 5 | 6 | // Allows access to backend functions 7 | const { remote } = require('electron') 8 | const backend = remote.require('./main.js') 9 | 10 | export default class Command extends React.Component { 11 | constructor(props) { 12 | super(props) 13 | 14 | this.state = { 15 | command: '' 16 | } 17 | } 18 | 19 | onTextChange = (e) => { 20 | // SetState with dynamic name 21 | const { id, value } = e.target 22 | this.setState({ [id]: value }) 23 | } 24 | 25 | onClickSubmit = (e) => { 26 | backend.execProcess(this.state.command, this.execProcessCallBack) 27 | e.preventDefault(); 28 | } 29 | 30 | execProcessCallBack = (str) => { 31 | document.getElementById("execProcessCallBack").innerHTML += "
" + str + "
" 32 | } 33 | 34 | render() { 35 | return ( 36 |
37 |

source: command.js

38 |

Execute OS commands via node (exec).

39 |

Examples:

40 |
    41 |
  • Linux: ping localhost -c 3
  • 42 |
  • Windows: ping localhost
  • 43 |
44 | 45 |
{ this.onClickSubmit(event) }}> 46 | { this.onTextChange(event) }} 49 | /> 50 | 51 | {" "} 52 | 53 | EXECUTE 54 | 55 | {" "} 56 | { document.getElementById("execProcessCallBack").innerHTML = "" }}> 57 | CLEAN 58 | 59 | 60 | 61 | {/* Exibe callback do back-end */} 62 |
63 | 64 |
65 | ) 66 | } 67 | } -------------------------------------------------------------------------------- /src/components/fs_inifile.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import AppButton from './app-button' 4 | 5 | var fs = require('fs') // Enable access to the File System: https://nodejs.org/api/fs.html 6 | var ini = require('ini') // INI manipulation tools 7 | var fName = "./reactron.ini" 8 | 9 | export default class FS_Inifile extends React.Component { 10 | constructor(props) { 11 | super(props) 12 | 13 | this.state = { 14 | iniContent: "", 15 | filesOpened: "" 16 | } 17 | 18 | // If Ini doesn't exist, create 19 | fs.exists(fName, (exists) => { 20 | if (!exists) { 21 | fs.writeFileSync(fName, "[files]") 22 | console.log(fName + " criado com sucesso!") 23 | } 24 | }); 25 | } 26 | 27 | selectFiles = (event) => { 28 | var input = event.target; 29 | var files = input.files; 30 | 31 | // "Scan" selected files 32 | let cFiles = "" 33 | for (var i = 0; i < files.length; i++) { 34 | cFiles += files[i].path + '\n' 35 | } 36 | 37 | // Update state with selected files 38 | this.setState({ filesOpened: cFiles }) 39 | } 40 | 41 | fileSystem_Ini = () => { 42 | // Open reacton.ini file at the same level as the executable 43 | var fIni = ini.parse(fs.readFileSync(fName, 'utf-8')) 44 | 45 | // Insert lines in INI 46 | fIni.Escopo = 'Scope variable ' 47 | fIni.files.file1 = "file1.png" 48 | fIni.files.file2 = "file2.png" 49 | fIni.files.file3 = "file3.png" 50 | 51 | // Delete file2 52 | delete fIni.files.file2 53 | 54 | // Save file INI 55 | fs.writeFileSync(fName, ini.stringify(fIni)) 56 | 57 | // Update state with the contents of the ini file 58 | this.setState({ iniContent: ini.stringify(fIni) }) 59 | } 60 | 61 | render() { 62 | return ( 63 |
64 |

source: fs_inifile.js

65 | 66 |

File Manipulation / Ini Files...

67 |

In this example we are going to manipulate local files based on INI files.

68 | 69 | {/* Selecao de arquivos */} 70 | { this.selectFiles(event) }} /> 77 | 82 |

Selected files

83 |
{this.state.filesOpened}
84 | 85 | {/* Manipulacao de arquivos INI */} 86 | { this.fileSystem_Ini() }}>Create/Open INI file 87 |

INI File Contents

88 |
{this.state.iniContent}
89 | 90 |
91 | ) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/components/rest.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | var http = require('http') 3 | 4 | export default class Rest extends React.Component { 5 | constructor(props) { 6 | super(props) 7 | 8 | this.state = { 9 | return_rest: "", 10 | status: "", 11 | headers: "" 12 | } 13 | 14 | this.callRest() 15 | } 16 | 17 | callRest = () => { 18 | var options = { 19 | host: 'localhost', 20 | port: 3333, 21 | path: '/url?name=MANSANO%20S/A&year=2019', 22 | method: 'GET' 23 | } 24 | 25 | const req = http.request(options, (res) => { 26 | this.setState({ status: res.statusCode }) 27 | this.setState({ headers: JSON.stringify(res.headers) }) 28 | 29 | res.setEncoding('utf8'); 30 | res.on('data', (chunk) => { 31 | this.setState({ return_rest: chunk }) 32 | }); 33 | }).end(); 34 | 35 | req.on('error', (e) => { 36 | this.setState({ return_rest: e.message }) 37 | }); 38 | } 39 | 40 | render() { 41 | return ( 42 |
43 |

source: rest.js

44 |

Consuming Rest

45 |

In the sample_rest folder there is a simple Rest server program

46 |

Start with the command: node index.js

47 | 48 |

Return from REST will be the sending parameters:

49 |
    50 |
  • Return: {this.state.return_rest}
  • 51 |
  • Status: {this.state.status}
  • 52 |
  • Headers: {this.state.headers}
  • 53 |
54 |
55 | ) 56 | } 57 | } -------------------------------------------------------------------------------- /src/components/welcome.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Home extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

source: welcome.js

8 |

Welcome ...

9 |

This program is a base project for a React/Electron/Material-UI application.

10 |
11 | ) 12 | } 13 | } -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0px; 3 | } 4 | 5 | .mainContent { 6 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; 7 | margin: 0px; 8 | border: 3px solid #494440; 9 | } 10 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Reactron 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './app.js'; 4 | 5 | window.onload = () => { 6 | ReactDOM.render(, document.getElementById('app')); 7 | }; 8 | --------------------------------------------------------------------------------