├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── afterinst.sh ├── appbkg.png ├── appdmg.json ├── buildall ├── flows.json ├── flows_cred.json ├── loading.gif ├── main.js ├── makewin32.js ├── makewin64.js ├── nodered.icns ├── nodered.ico ├── nodered.png └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | dist/* 25 | lib/* 26 | build/* 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | .config.json 32 | .flows.json.backup 33 | .sessions.json 34 | *darwin-x64* 35 | *linux-x64* 36 | *win32-x64* 37 | *.back 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Use OSX as env to build in 2 | language: objective-c 3 | cache: 4 | directories: 5 | - node_modules 6 | env: 7 | # Node in order to install it by running the command individually, here to specify the version 8 | #- NODE_VERSION="4.6" 9 | before_install: 10 | # Install brew -> wine and makensis 11 | - brew update 12 | - brew install libusb 13 | - brew install wine 14 | - wine --version 15 | - brew install makensis 16 | # Install the nvm. Nvm is not included by default in OS X environment of Travis 17 | - git clone https://github.com/creationix/nvm.git /tmp/.nvm 18 | - source /tmp/.nvm/nvm.sh 19 | - nvm install 4.6 20 | - nvm use --delete-prefix 4.6 21 | - node --version 22 | - npm -v 23 | - npm install -g electron-packager 24 | - npm install -g appdmg 25 | install: 26 | - npm install 27 | script: 28 | - npm run build 29 | #deploy: 30 | # skip_cleanup: true 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | ================== 3 | 4 | Statement of Purpose 5 | --------------------- 6 | 7 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 8 | 9 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 10 | 11 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 12 | 13 | 1. Copyright and Related Rights. 14 | -------------------------------- 15 | A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 16 | 17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 18 | ii. moral rights retained by the original author(s) and/or performer(s); 19 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 20 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 21 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work; 22 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 23 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 24 | 25 | 2. Waiver. 26 | ----------- 27 | To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 28 | 29 | 3. Public License Fallback. 30 | ---------------------------- 31 | Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 32 | 33 | 4. Limitations and Disclaimers. 34 | -------------------------------- 35 | 36 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 37 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 38 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 39 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-node-red 2 | 3 | This is an Electron template to embed Node-RED with a Dashboard generated by node-red-dashboard. 4 | 5 | You can base off this model and update the package.json file to include your own required dependencies. 6 | 7 | ## To Use 8 | 9 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line: 10 | 11 | ```bash 12 | # Clone this repository 13 | git clone https://github.com/dceejay/electron-node-red.git 14 | # Go into the repository 15 | cd electron-node-red 16 | # Install dependencies and run the app 17 | npm install && npm run clean && npm start 18 | ``` 19 | 20 | ## TL:DR - building runtimes 21 | 22 | On OSX you can run `./buildall` to build binaries of "everything"... maybe... 23 | 24 | Run `npm run pack` to create packages for all platforms - these are the files required to run, they are not binary installers. 25 | 26 | Builds are created in the `build` directory. Runtimes are created in the `../electron-bin` directory. 27 | 28 | **Note**: this was written to work on a Mac... other tools may/will be needed on other platforms. 29 | 30 | ## Packaging your application 31 | 32 | If you want to distribute executables of this project, the easiest way is to use electron-packager: 33 | 34 | ``` 35 | sudo npm install -g electron-packager 36 | 37 | # build for OSX 64 bits 38 | electron-packager . Node-RED --icon=nodered.icns --platform=darwin --arch=x64 --out=build --overwrite 39 | 40 | # build for Windows 64 bits 41 | electron-packager . Node-RED --icon=nodered.icns --platform=win32 --arch=x64 --out=build --asar=true --overwrite --win32metadata.CompanyName='IBM Corp.' --win32metadata.ProductName='Node-RED Electron' 42 | 43 | # build for Linux 64 bits 44 | electron-packager . Node-RED --icon=nodered.icns --platform=linux --arch=x64 --out=build --overwrite 45 | ``` 46 | 47 | Learn more about Electron and its API in the [documentation](http://electron.atom.io/docs/latest). 48 | 49 | 50 | ### To package as a dmg 51 | 52 | `npm run build:osx` 53 | 54 | look at `https://github.com/LinusU/node-appdmg` 55 | 56 | sudo npm install -g appdmg 57 | 58 | appdmg appdmg.json ~/Desktop/NodeRED.dmg 59 | 60 | 61 | ### To package as a deb 62 | 63 | `npm run build:linux64` or `npm run build:linux32` - for Intel Linux 64 | 65 | Look at `https://github.com/jordansissel/fpm` 66 | 67 | fpm -s dir -t deb -f -n node-red-electron -v 0.16.2 -m your-email@example.com -a i386 Node-RED-linux-ia32/ 68 | fpm -s dir -t deb -f -n node-red-electron -v 0.16.2 -m your-email@example.com -a x86_64 Node-RED-linux-x64/ 69 | 70 | Use **sudo dpkg -i ...*** to install the correct deb for your architecture. 71 | 72 | Use `Node-RED` command to run. Flows are stored in `~/.node-red`. 73 | 74 | 75 | ### To package as an exe 76 | 77 | `npm run build:win32` - to build for 32-bit Windows. 78 | 79 | `npm run build:win64` - to build for 64-bit Windows. 80 | 81 | **Note**: This project was built to run on Mac OSX - To build for windows on other platforms you may need to use other tools. 82 | 83 | 84 | ## License [CC0 (Public Domain)](LICENSE.md) 85 | 86 | ## See also 87 | - **Stand-alone Starter Project** - https://github.com/dceejay/node-red-project-starter 88 | - **Bluemix Starter Project** - https://github.com/dceejay/node-red-bluemix-starter 89 | -------------------------------------------------------------------------------- /afterinst.sh: -------------------------------------------------------------------------------- 1 | ln -s /opt/node-red/Node-RED /usr/bin/Node-RED 2 | -------------------------------------------------------------------------------- /appbkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natcl/electron-node-red/a673babea94209927f9feb45f7582afb0b9dd393/appbkg.png -------------------------------------------------------------------------------- /appdmg.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Node-RED Electron installer", 3 | "icon": "nodered.icns", 4 | "background": "appbkg.png", 5 | "icon-size": 80, 6 | "contents": [ 7 | { "x": 448, "y": 344, "type": "link", "path": "/Applications" }, 8 | { "x": 192, "y": 344, "type": "file", "path": "build/Node-RED-darwin-x64/Node-RED.app" } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /buildall: -------------------------------------------------------------------------------- 1 | npm i 2 | #cd node_modules/electron-winstaller 3 | #npm i is-property 4 | #cd ../.. 5 | rm -rf node_modules/node-red/node_modules/node-red-node-serialport node_modules/node-red/node_modules/node-red-node-feedparser node_modules/node-red/node_modules/node-red-node-email 6 | ./node_modules/.bin/electron-rebuild 7 | npm run clean 8 | npm run build:osx 9 | rm -rf build/ 10 | npm run build:linux32 11 | rm -rf build/ 12 | npm run build:linux64 13 | rm -rf build/ 14 | npm run build:win32 15 | rm -rf build/ ../electron-bin/*.nupkg ../electron-bin/RELEASES 16 | npm run build:win64 17 | rm -rf build/ ../electron-bin/*.nu* ../electron-bin/RELEASES 18 | -------------------------------------------------------------------------------- /flows.json: -------------------------------------------------------------------------------- 1 | [{"id":"41f61d2.fbe09e4","type":"tab","label":"Flow 1"},{"id":"52a903f3.ad56fc","type":"ui_tab","z":"41f61d2.fbe09e4","name":"Home","icon":"dashboard"},{"id":"30e652f.d9de3ae","type":"ui_group","z":"41f61d2.fbe09e4","name":"Panel 2","tab":"52a903f3.ad56fc","order":3,"disp":true,"width":"6"},{"id":"a8ecb9.c60f4348","type":"ui_group","z":"41f61d2.fbe09e4","name":"Introduction","tab":"52a903f3.ad56fc","order":1,"disp":false,"width":"3"},{"id":"bbdf3e02.e8fee","type":"ui_group","z":"41f61d2.fbe09e4","name":"Panel 1","tab":"52a903f3.ad56fc","order":2,"disp":true,"width":"6"},{"id":"d9ba26fa.6d2b18","type":"ui_base","theme":{"name":"theme-light","lightTheme":{"default":"#0094CE","baseColor":"#8e0d17","baseFont":"Copperplate,Copperplate Gothic Light,fantasy","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"Helvetica Neue","edited":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"Helvetica Neue"},"themeState":{"base-color":{"default":"#0094CE","value":"#d80005","edited":true},"page-titlebar-backgroundColor":{"value":"#8e0d17","edited":false},"page-backgroundColor":{"value":"#fafafa","edited":false},"page-sidebar-backgroundColor":{"value":"#000000","edited":false},"group-textColor":{"value":"#d41322","edited":false},"group-borderColor":{"value":"#ffffff","edited":false},"group-backgroundColor":{"value":"#ffffff","edited":false},"widget-textColor":{"value":"#111111","edited":false},"widget-backgroundColor":{"value":"#8e0d17","edited":false},"widget-borderColor":{"value":"#ffffff","edited":false},"base-font":{"value":"Copperplate,Copperplate Gothic Light,fantasy"}}},"site":{"name":"Node-RED Dashboard","hideToolbar":"false","allowSwipe":"false","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"87356b62.92e3d8","type":"ui_group","z":"","name":"Text to Speech","tab":"52a903f3.ad56fc","order":5,"disp":true,"width":"6"},{"id":"c75ad4f0.0cede8","type":"ui_group","z":"","name":"Map","tab":"52a903f3.ad56fc","order":4,"disp":true,"width":"6"},{"id":"189cf871.681118","type":"ui_template","z":"41f61d2.fbe09e4","group":"a8ecb9.c60f4348","name":"Welcome","order":1,"width":"3","height":"9","format":"

Welcome to the Node-RED Dashboard

\n

On the right you will see a graph and a chart logging data from the sliders underneath.

","storeOutMessages":false,"fwdInMessages":false,"x":93,"y":45,"wires":[[]]},{"id":"9f19ee5c.beaef","type":"ui_chart","z":"41f61d2.fbe09e4","name":"","group":"bbdf3e02.e8fee","order":1,"width":"0","height":"0","label":"","chartType":"line","xformat":"HH:mm:ss","interpolate":"basis","nodata":"No Data","dot":false,"ymin":"0","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":"","colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":270,"y":200,"wires":[[],[]]},{"id":"799d9318.fd385c","type":"ui_gauge","z":"41f61d2.fbe09e4","name":"","group":"30e652f.d9de3ae","order":2,"width":"","height":"","gtype":"gage","title":"Title","label":"gauge","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"x":270,"y":140,"wires":[]},{"id":"6f18b200.666a4","type":"ui_button","z":"41f61d2.fbe09e4","name":"","group":"87356b62.92e3d8","order":2,"width":0,"height":0,"label":"press to talk","color":"","bgcolor":"","icon":"fa-volume-up","payload":"Hello to Jason Isaacs","payloadType":"str","topic":"","x":110,"y":300,"wires":[["f897d7c2.467a58"]]},{"id":"f897d7c2.467a58","type":"ui_audio","z":"41f61d2.fbe09e4","name":"","group":"30e652f.d9de3ae","voice":"0","x":300,"y":300,"wires":[]},{"id":"da0f7e67.0d38a","type":"ui_slider","z":"41f61d2.fbe09e4","name":"","label":"slider","group":"30e652f.d9de3ae","order":4,"width":0,"height":0,"passthru":true,"topic":"","min":0,"max":"100","step":1,"x":90,"y":140,"wires":[["799d9318.fd385c"]]},{"id":"eabf2bd7.f4e0c8","type":"ui_slider","z":"41f61d2.fbe09e4","name":"","label":"slider","group":"bbdf3e02.e8fee","order":4,"width":0,"height":0,"passthru":true,"topic":"","min":0,"max":"100","step":1,"x":90,"y":200,"wires":[["9f19ee5c.beaef"]]},{"id":"7d549f6e.58ab6","type":"worldmap","z":"41f61d2.fbe09e4","name":"","lat":"","lon":"","zoom":"","layer":"OSM","cluster":"","maxage":"","usermenu":"hide","panit":"true","x":445,"y":411,"wires":[]},{"id":"45508d88.744a54","type":"function","z":"41f61d2.fbe09e4","name":"","func":"// create random position\nvar lat = 51 + Math.random() * 0.2;\nvar lon = -1.45 + Math.random() * 0.2;\nmsg.payload={lat:lat, lon:lon, name:\"Mike\", icon:\"male\", url:\"IBM link\"};\nreturn msg;","outputs":1,"noerr":0,"x":265,"y":411,"wires":[["7d549f6e.58ab6"]]},{"id":"6ca8cfc2.e0bce","type":"ui_button","z":"41f61d2.fbe09e4","name":"","group":"c75ad4f0.0cede8","order":1,"width":0,"height":0,"label":"Move Mike","color":"","bgcolor":"#910000","icon":"fa-male","payload":"","payloadType":"str","topic":"","x":103,"y":412,"wires":[["45508d88.744a54"]]},{"id":"c87aa53d.223ba8","type":"inject","z":"41f61d2.fbe09e4","name":"","topic":"","payload":"/worldmap","payloadType":"str","repeat":"","crontab":"","once":true,"x":106,"y":461,"wires":[["42a56979.e10b68"]]},{"id":"582c9a7e.d9d014","type":"ui_template","z":"41f61d2.fbe09e4","group":"c75ad4f0.0cede8","name":"","order":2,"width":"6","height":"6","format":"
","storeOutMessages":true,"fwdInMessages":true,"x":436,"y":461,"wires":[[]]},{"id":"42a56979.e10b68","type":"template","z":"41f61d2.fbe09e4","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"","x":266,"y":461,"wires":[["582c9a7e.d9d014"]]}] -------------------------------------------------------------------------------- /flows_cred.json: -------------------------------------------------------------------------------- 1 | {"$":"7b15c36b8209a9e08997cdea6bd0c71cpNQ="} -------------------------------------------------------------------------------- /loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natcl/electron-node-red/a673babea94209927f9feb45f7582afb0b9dd393/loading.gif -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | // Some settings you can edit easily 5 | // Flows file name 6 | const flowfile = 'flows.json'; 7 | // Start on the dashboard page 8 | const url = "/ui"; 9 | // url for the editor page 10 | const urledit = "/admin"; 11 | // tcp port to use 12 | //const listenPort = "18880"; // fix it just because 13 | const listenPort = parseInt(Math.random()*16383+49152) // or random ephemeral port 14 | 15 | const os = require('os'); 16 | const electron = require('electron'); 17 | const app = electron.app; 18 | const BrowserWindow = electron.BrowserWindow; 19 | const {Menu, MenuItem} = electron; 20 | 21 | // this should be placed at top of main.js to handle squirrel setup events quickly 22 | if (handleSquirrelEvent()) { return; } 23 | 24 | var http = require('http'); 25 | var express = require("express"); 26 | var RED = require("node-red"); 27 | 28 | // Create an Express app 29 | var red_app = express(); 30 | 31 | // Add a simple route for static content served from 'public' 32 | //red_app.use(express.static(__dirname +"/public")); 33 | 34 | // Create a server 35 | var server = http.createServer(red_app); 36 | 37 | var userdir; 38 | if (process.argv[1] && (process.argv[1] === "main.js")) { 39 | userdir = __dirname; 40 | } 41 | else { // We set the user directory to be in the users home directory... 42 | const fs = require('fs'); 43 | userdir = os.homedir() + '/.node-red'; 44 | if (!fs.existsSync(userdir)) { 45 | fs.mkdirSync(userdir); 46 | } 47 | if (!fs.existsSync(userdir+"/"+flowfile)) { 48 | fs.writeFileSync(userdir+"/"+flowfile, fs.readFileSync(__dirname+"/"+flowfile)); 49 | } 50 | } 51 | console.log("Setting UserDir to ",userdir); 52 | 53 | // Create the settings object - see default settings.js file for other options 54 | var settings = { 55 | verbose: true, 56 | httpAdminRoot:"/admin", 57 | httpNodeRoot: "/", 58 | userDir: userdir, 59 | flowFile: flowfile, 60 | functionGlobalContext: { } // enables global context 61 | }; 62 | 63 | // Initialise the runtime with a server and settings 64 | RED.init(server,settings); 65 | 66 | // Serve the editor UI from /red 67 | red_app.use(settings.httpAdminRoot,RED.httpAdmin); 68 | 69 | // Serve the http nodes UI from /api 70 | red_app.use(settings.httpNodeRoot,RED.httpNode); 71 | 72 | // Create the Application's main menu 73 | var template = [{ 74 | label: "Application", 75 | submenu: [ 76 | { role: 'about' }, 77 | { type: "separator" }, 78 | { role: 'quit' } 79 | ]}, { 80 | label: 'Node-RED', 81 | submenu: [ 82 | { label: 'Dashboard', 83 | accelerator: "Shift+CmdOrCtrl+D", 84 | click() { mainWindow.loadURL("http://localhost:"+listenPort+url); } 85 | }, 86 | { label: 'Editor', 87 | accelerator: "Shift+CmdOrCtrl+E", 88 | click() { mainWindow.loadURL("http://localhost:"+listenPort+urledit); } 89 | }, 90 | { type: 'separator' }, 91 | { label: 'Documentation', 92 | click() { require('electron').shell.openExternal('http://nodered.org/docs') } 93 | }, 94 | { label: 'Flows and Nodes', 95 | click() { require('electron').shell.openExternal('http://flows.nodered.org') } 96 | }, 97 | { label: 'Google group', 98 | click() { require('electron').shell.openExternal('https://groups.google.com/forum/#!forum/node-red') } 99 | } 100 | ]}, { 101 | label: "Edit", 102 | submenu: [ 103 | { label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" }, 104 | { label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" }, 105 | { type: "separator" }, 106 | { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" }, 107 | { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" }, 108 | { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" }, 109 | { label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" } 110 | ]}, { 111 | label: 'View', 112 | submenu: [ 113 | { label: 'Reload', 114 | accelerator: 'CmdOrCtrl+R', 115 | click(item, focusedWindow) { if (focusedWindow) focusedWindow.reload(); } 116 | }, 117 | { label: 'Toggle Developer Tools', 118 | accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', 119 | click(item, focusedWindow) { if (focusedWindow) focusedWindow.webContents.toggleDevTools(); } 120 | }, 121 | { type: 'separator' }, 122 | { role: 'resetzoom' }, 123 | { role: 'zoomin' }, 124 | { role: 'zoomout' }, 125 | { type: 'separator' }, 126 | { role: 'togglefullscreen' }, 127 | { role: 'minimize' } 128 | ]} 129 | ]; 130 | 131 | // Keep a global reference of the window object, if you don't, the window will 132 | // be closed automatically when the JavaScript object is garbage collected. 133 | let mainWindow; 134 | 135 | function createWindow() { 136 | // Create the browser window. 137 | mainWindow = new BrowserWindow({ 138 | autoHideMenuBar: true, 139 | webPreferences: { 140 | nodeIntegration: false 141 | }, 142 | title: "Node-RED", 143 | fullscreenable: true, 144 | //titleBarStyle: "hidden", 145 | width: 1024, 146 | height: 768, 147 | icon: __dirname + "/nodered.png" 148 | }); 149 | 150 | var webContents = mainWindow.webContents; 151 | webContents.on('did-get-response-details', function(event, status, newURL, originalURL, httpResponseCode) { 152 | if ((httpResponseCode == 404) && (newURL == ("http://localhost:"+listenPort+url))) { 153 | setTimeout(webContents.reload, 200); 154 | } 155 | Menu.setApplicationMenu(Menu.buildFromTemplate(template)); 156 | }); 157 | 158 | // Open the DevTools. 159 | //mainWindow.webContents.openDevTools(); 160 | 161 | mainWindow.webContents.on("new-window", function(e, url, frameName, disposition, options) { 162 | // if a child window opens... modify any other options such as width/height, etc 163 | // in this case make the child overlap the parent exactly... 164 | var w = mainWindow.getBounds(); 165 | options.x = w.x; 166 | options.y = w.y; 167 | options.width = w.width; 168 | options.height = w.height; 169 | //re-use the same child name so all "2nd" windows use the same one. 170 | //frameName = "child"; 171 | }) 172 | 173 | // Emitted when the window is closed. 174 | mainWindow.on('closed', function() { 175 | // Dereference the window object, usually you would store windows 176 | // in an array if your app supports multi windows, this is the time 177 | // when you should delete the corresponding element. 178 | mainWindow = null; 179 | }); 180 | } 181 | 182 | // Called when Electron has finished initialization and is ready to create browser windows. 183 | app.on('ready', createWindow); 184 | 185 | // Quit when all windows are closed. 186 | app.on('window-all-closed', function () { 187 | // On OS X it is common for applications and their menu bar 188 | // to stay active until the user quits explicitly with Cmd + Q 189 | if (process.platform !== 'darwin') { 190 | app.quit(); 191 | } 192 | }); 193 | 194 | app.on('activate', function() { 195 | // On OS X it's common to re-create a window in the app when the 196 | // dock icon is clicked and there are no other windows open. 197 | if (mainWindow === null) { 198 | createWindow(); 199 | mainWindow.loadURL("http://127.0.0.1:"+listenPort+url); 200 | } 201 | }); 202 | 203 | // Start the Node-RED runtime, then load the inital page 204 | RED.start().then(function() { 205 | server.listen(listenPort,"127.0.0.1",function() { 206 | mainWindow.loadURL("http://127.0.0.1:"+listenPort+url); 207 | }); 208 | }); 209 | 210 | /////////////////////////////////////////////////////// 211 | // All this Squirrel stuff is for the Windows installer 212 | function handleSquirrelEvent() { 213 | if (process.argv.length === 1) { 214 | return false; 215 | } 216 | 217 | const ChildProcess = require('child_process'); 218 | const path = require('path'); 219 | 220 | const appFolder = path.resolve(process.execPath, '..'); 221 | const rootAtomFolder = path.resolve(appFolder, '..'); 222 | const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe')); 223 | const exeName = path.basename(process.execPath); 224 | 225 | const spawn = function(command, args) { 226 | let spawnedProcess, error; 227 | 228 | try { 229 | spawnedProcess = ChildProcess.spawn(command, args, {detached: true}); 230 | } catch (error) {} 231 | 232 | return spawnedProcess; 233 | }; 234 | 235 | const spawnUpdate = function(args) { 236 | return spawn(updateDotExe, args); 237 | }; 238 | 239 | const squirrelEvent = process.argv[1]; 240 | switch (squirrelEvent) { 241 | case '--squirrel-install': 242 | case '--squirrel-updated': 243 | // Optionally do things such as: 244 | // - Add your .exe to the PATH 245 | // - Write to the registry for things like file associations and 246 | // explorer context menus 247 | 248 | // Install desktop and start menu shortcuts 249 | spawnUpdate(['--createShortcut', exeName]); 250 | 251 | setTimeout(app.quit, 1000); 252 | return true; 253 | 254 | case '--squirrel-uninstall': 255 | // Undo anything you did in the --squirrel-install and 256 | // --squirrel-updated handlers 257 | 258 | // Remove desktop and start menu shortcuts 259 | spawnUpdate(['--removeShortcut', exeName]); 260 | 261 | setTimeout(app.quit, 1000); 262 | return true; 263 | 264 | case '--squirrel-obsolete': 265 | // This is called on the outgoing version of your app before 266 | // we update to the new version - it's the opposite of 267 | // --squirrel-updated 268 | 269 | app.quit(); 270 | return true; 271 | } 272 | }; 273 | -------------------------------------------------------------------------------- /makewin32.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | var electronInstaller = require('electron-winstaller'); 3 | var fs = require('fs'); 4 | 5 | if (fs.existsSync('build/Node-RED-win32-ia32')) { 6 | console.log("Building setup app for Windows 32bit"); 7 | resultPromise = electronInstaller.createWindowsInstaller({ 8 | appDirectory: 'build/Node-RED-win32-ia32', 9 | outputDirectory: 'executable/electron-win32-ia32/', 10 | authors: 'IBM Corp.', 11 | exe: 'Node-RED.exe', 12 | setupExe: 'Node-RED-Electron-ia32.exe', 13 | setupIcon: 'nodered.ico', 14 | loadingGif: 'loading.gif', 15 | skipUpdateIcon: true 16 | }); 17 | resultPromise.then( 18 | () => console.log("32bit build completed."), 19 | (e) => console.log(`32bit build failed: ${e.message}`) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /makewin64.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | var electronInstaller = require('electron-winstaller'); 3 | var fs = require('fs'); 4 | 5 | if (fs.existsSync('build/Node-RED-win32-x64')) { 6 | console.log("Building setup app for Windows 64bit"); 7 | resultPromise = electronInstaller.createWindowsInstaller({ 8 | appDirectory: 'build/Node-RED-win32-x64', 9 | outputDirectory: 'executable/electron-win32-x64/', 10 | authors: 'IBM Corp.', 11 | exe: 'Node-RED.exe', 12 | setupExe: 'Node-RED-Electron-x64.exe', 13 | setupIcon: 'nodered.ico', 14 | loadingGif: 'loading.gif', 15 | skipUpdateIcon: true 16 | }); 17 | resultPromise.then( 18 | () => console.log("64bit build completed."), 19 | (e) => console.log(`64bit build failed: ${e.message}`) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /nodered.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natcl/electron-node-red/a673babea94209927f9feb45f7582afb0b9dd393/nodered.icns -------------------------------------------------------------------------------- /nodered.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natcl/electron-node-red/a673babea94209927f9feb45f7582afb0b9dd393/nodered.ico -------------------------------------------------------------------------------- /nodered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natcl/electron-node-red/a673babea94209927f9feb45f7582afb0b9dd393/nodered.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron_node_red", 3 | "version": "0.17.4", 4 | "description": "Electron Node-RED application starter", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron main.js", 8 | "test": "echo \" Warning: no test specified \"", 9 | "watch": "nodemon --exec \"npm run start\" --ext js,css,json --ignore build/", 10 | 11 | "clean": "rm -rf ./build ../electron-bin && mkdir -p ./build ../electron-bin", 12 | 13 | "pack": "npm run clean && electron-packager . Node-RED --icon=nodered.icns --all --out=build --overwrite", 14 | "pack:osx": "electron-packager . Node-RED --icon=nodered.icns --platform=darwin --arch=x64 --out=build --overwrite", 15 | "pack:linux32": "electron-packager . Node-RED --icon=nodered.icns --platform=linux --arch=ia32 --out=build --overwrite && cp afterinst.sh build/Node-RED-linux-ia32/", 16 | "pack:linux64": "electron-packager . Node-RED --icon=nodered.icns --platform=linux --arch=x64 --out=build --overwrite && cp afterinst.sh build/Node-RED-linux-x64", 17 | "pack:win32": "electron-packager . Node-RED --icon=nodered.icns --platform=win32 --arch=ia32 --out=build --asar --overwrite --win32metadata.CompanyName='IBM Corp.' --win32metadata.ProductName='Node-RED Electron'", 18 | "pack:win64": "electron-packager . Node-RED --icon=nodered.icns --platform=win32 --arch=x64 --out=build --asar --overwrite --win32metadata.CompanyName='IBM Corp.' --win32metadata.ProductName='Node-RED Electron'", 19 | "pack:armv7l": "electron-packager . Node-RED --icon=nodered.icns --platform=linux --arch=armv7l --out=build --overwrite && cp afterinst.sh build/Node-RED-linux-armv7l", 20 | 21 | "build": "npm run clean && npm run build:osx && npm run build:linux64 && npm run build:linux32", 22 | "build:osx": "npm run pack:osx && appdmg appdmg.json ../electron-bin/Node-RED-Electron_$npm_package_version.dmg", 23 | "build:linux32": "npm run pack:linux32 && fpm -s dir -t deb -f -n node-red-electron -v $npm_package_version -m conway@uk.ibm.com -a i386 -p ../electron-bin -C build/Node-RED-linux-ia32 --prefix=/opt/node-red --after-install=afterinst.sh ./", 24 | "build:linux64": "npm run pack:linux64 && fpm -s dir -t deb -f -n node-red-electron -v $npm_package_version -m conway@uk.ibm.com -a x86_64 -p ../electron-bin -C build/Node-RED-linux-x64 --prefix=/opt/node-red --after-install=afterinst.sh ./", 25 | "build:win32": "npm run pack:win32 && node makewin32.js", 26 | "build:win64": "npm run pack:win64 && node makewin64.js", 27 | "build:armv7l": "npm run pack:armv7l && fpm -s dir -t deb -f -n node-red-electron -v $npm_package_version -m conway@uk.ibm.com -a armv7l -p ../electron-bin -C build/Node-RED-linux-armv7l --prefix=/opt/node-red --after-install=afterinst.sh ./" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/dceejay/electron-node-red.git" 32 | }, 33 | "dependencies": { 34 | "node-red": "*", 35 | "node-red-dashboard": "*", 36 | "node-red-contrib-web-worldmap": "*", 37 | "node-red-node-geofence": "*", 38 | "node-red-node-random": "*", 39 | "node-red-node-smooth": "*", 40 | "node-red-contrib-play-audio": "*", 41 | "node-red-node-base64": "*", 42 | "express": "^4.14.0" 43 | }, 44 | "keywords": [ 45 | "electron", 46 | "quick start", 47 | "node-red" 48 | ], 49 | "contributors": [ 50 | {"name":"Dave Conway-Jones"}, 51 | {"name":"Nathanaël Lécaudé"} 52 | ], 53 | "license": "Apache-2.0", 54 | "bugs": { 55 | "url": "https://github.com/dceejay/electron-node-red/issues" 56 | }, 57 | "homepage": "https://github.com/dceejay/electron-node-red#readme", 58 | "devDependencies": { 59 | "electron": "^1.6.11", 60 | "electron-rebuild": "*", 61 | "electron-squirrel-startup": "*", 62 | "electron-winstaller": "2.5.2" 63 | } 64 | } 65 | --------------------------------------------------------------------------------