Switch electron boilerplates
|
@ -1,52 +0,0 @@
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Dependency directory
|
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
# OSX
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# flow-typed
|
|
||||||
flow-typed/npm/*
|
|
||||||
!flow-typed/npm/module_vx.x.x.js
|
|
||||||
|
|
||||||
# App packaged
|
|
||||||
release
|
|
||||||
app/main.prod.js
|
|
||||||
app/main.prod.js.map
|
|
||||||
app/renderer.prod.js
|
|
||||||
app/renderer.prod.js.map
|
|
||||||
app/style.css
|
|
||||||
app/style.css.map
|
|
||||||
dist
|
|
||||||
dll
|
|
||||||
main.js
|
|
||||||
main.js.map
|
|
||||||
|
|
||||||
.idea
|
|
||||||
npm-debug.log.*
|
|
||||||
.*.dockerfile
|
|
13
Dashboard/.editorconfig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{js,json,css,html}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
9
Dashboard/.eslintignore
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
cache
|
||||||
|
lib
|
||||||
|
dist
|
||||||
|
webpack.*.js
|
||||||
|
server.js
|
||||||
|
build.js
|
||||||
|
init.js
|
37
Dashboard/.eslintrc
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true,
|
||||||
|
"modules": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": [ "react" ],
|
||||||
|
"rules": {
|
||||||
|
"prefer-const": "warn",
|
||||||
|
"no-console": "off",
|
||||||
|
"no-loop-func": "warn",
|
||||||
|
"new-cap": "off",
|
||||||
|
"no-param-reassign": "warn",
|
||||||
|
"func-names": "off",
|
||||||
|
"no-unused-expressions" : "error",
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"react/prop-types": "off"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"pragma": "React",
|
||||||
|
"version": "16.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
[ignore]
|
|
||||||
<PROJECT_ROOT>/app/main.prod.js
|
|
||||||
<PROJECT_ROOT>/app/main.prod.js.map
|
|
||||||
<PROJECT_ROOT>/app/dist/.*
|
|
||||||
<PROJECT_ROOT>/resources/.*
|
|
||||||
<PROJECT_ROOT>/node_modules/webpack-cli
|
|
||||||
<PROJECT_ROOT>/release/.*
|
|
||||||
<PROJECT_ROOT>/dll/.*
|
|
||||||
<PROJECT_ROOT>/release/.*
|
|
||||||
<PROJECT_ROOT>/git/.*
|
|
||||||
|
|
||||||
[include]
|
|
||||||
|
|
||||||
[libs]
|
|
||||||
|
|
||||||
[options]
|
|
||||||
esproposal.class_static_fields=enable
|
|
||||||
esproposal.class_instance_fields=enable
|
|
||||||
esproposal.export_star_as=enable
|
|
||||||
module.name_mapper.extension='css' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
|
|
||||||
module.name_mapper.extension='styl' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
|
|
||||||
module.name_mapper.extension='scss' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
|
|
||||||
module.name_mapper.extension='png' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'
|
|
||||||
module.name_mapper.extension='jpg' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'
|
|
||||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe
|
|
||||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
|
|
6
Dashboard/.gitattributes
vendored
|
@ -1,6 +0,0 @@
|
||||||
* text eol=lf
|
|
||||||
*.png binary
|
|
||||||
*.jpg binary
|
|
||||||
*.jpeg binary
|
|
||||||
*.ico binary
|
|
||||||
*.icns binary
|
|
25
Dashboard/.github/workflows/build.yml
vendored
|
@ -1,25 +0,0 @@
|
||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [10.x, 12.x, 14.x]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- run: yarn
|
|
||||||
- run: yarn package
|
|
52
Dashboard/.gitignore
vendored
|
@ -1,51 +1,5 @@
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Dependency directory
|
|
||||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
# OSX
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# flow-typed
|
|
||||||
flow-typed/npm/*
|
|
||||||
!flow-typed/npm/module_vx.x.x.js
|
|
||||||
|
|
||||||
# App packaged
|
|
||||||
release
|
|
||||||
app/main.prod.js
|
|
||||||
app/main.prod.js.map
|
|
||||||
app/renderer.prod.js
|
|
||||||
app/renderer.prod.js.map
|
|
||||||
app/style.css
|
|
||||||
app/style.css.map
|
|
||||||
dist
|
dist
|
||||||
dll
|
build
|
||||||
main.js
|
.DS_Store
|
||||||
main.js.map
|
*.log
|
||||||
|
|
||||||
.idea
|
|
||||||
npm-debug.log.*
|
|
||||||
|
|
10
Dashboard/.prettierrc.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# .prettierrc.yml
|
||||||
|
# see: https://prettier.io/docs/en/options.html
|
||||||
|
printWidth: 100
|
||||||
|
semi: true
|
||||||
|
singleQuote: true
|
||||||
|
trailingComma: all
|
||||||
|
bracketSpacing: true
|
||||||
|
jsxBracketSameLine: true
|
||||||
|
arrowParens: always
|
||||||
|
proseWrap: always
|
17
Dashboard/.travis.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: node_js
|
||||||
|
|
||||||
|
node_js:
|
||||||
|
- '10'
|
||||||
|
cache: npm
|
||||||
|
services:
|
||||||
|
- xvfb
|
||||||
|
|
||||||
|
install:
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
script:
|
||||||
|
- npm run check-format
|
||||||
|
- npm run lint
|
||||||
|
- npm test
|
8
Dashboard/.vscode/extensions.json
vendored
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"dzannotti.vscode-babel-coloring",
|
|
||||||
"EditorConfig.EditorConfig",
|
|
||||||
"flowtype.flow-for-vscode"
|
|
||||||
]
|
|
||||||
}
|
|
35
Dashboard/.vscode/settings.json
vendored
|
@ -1,35 +1,6 @@
|
||||||
{
|
{
|
||||||
"files.associations": {
|
|
||||||
".babelrc": "jsonc",
|
|
||||||
".eslintrc": "jsonc",
|
|
||||||
".prettierrc": "jsonc",
|
|
||||||
|
|
||||||
".stylelintrc": "json",
|
|
||||||
|
|
||||||
".dockerignore": "ignore",
|
|
||||||
".eslintignore": "ignore",
|
|
||||||
".flowconfig": "ignore"
|
|
||||||
},
|
|
||||||
|
|
||||||
"javascript.validate.enable": false,
|
|
||||||
"javascript.format.enable": false,
|
|
||||||
"typescript.validate.enable": false,
|
|
||||||
"typescript.format.enable": false,
|
|
||||||
|
|
||||||
"flow.useNPMPackagedFlow": true,
|
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
".git": true,
|
"build/": true,
|
||||||
".eslintcache": true,
|
"dist/": true
|
||||||
"app/dist": true,
|
|
||||||
"app/main.prod.js": true,
|
|
||||||
"app/main.prod.js.map": true,
|
|
||||||
"bower_components": true,
|
|
||||||
"dll": true,
|
|
||||||
"flow-typed": true,
|
|
||||||
"release": true,
|
|
||||||
"node_modules": true,
|
|
||||||
"npm-debug.log.*": true,
|
|
||||||
"test/**/__snapshots__": true,
|
|
||||||
"yarn.lock": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
74
Dashboard/README.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# electron-react-redux-boilerplate
|
||||||
|
[![Build Status](https://api.travis-ci.org/jschr/electron-react-redux-boilerplate.svg)](https://travis-ci.org/jschr/electron-react-redux-boilerplate)
|
||||||
|
[![dependencies Status](https://david-dm.org/jschr/electron-react-redux-boilerplate/status.svg)](https://david-dm.org/jschr/electron-react-redux-boilerplate)
|
||||||
|
[![devDependencies Status](https://david-dm.org/jschr/electron-react-redux-boilerplate/dev-status.svg)](https://david-dm.org/jschr/electron-react-redux-boilerplate?type=dev)
|
||||||
|
|
||||||
|
A minimal boilerplate to get started with [Electron](http://electron.atom.io/), [React](https://facebook.github.io/react/) and [Redux](http://redux.js.org/).
|
||||||
|
|
||||||
|
Including:
|
||||||
|
|
||||||
|
* [React Router](https://reacttraining.com/react-router/)
|
||||||
|
* [Redux Thunk](https://github.com/gaearon/redux-thunk/)
|
||||||
|
* [Redux Actions](https://github.com/acdlite/redux-actions/)
|
||||||
|
* [Redux Local Storage](https://github.com/elgerlambert/redux-localstorage/)
|
||||||
|
* [Electron Packager](https://github.com/electron-userland/electron-packager)
|
||||||
|
* [Electron DevTools Installer](https://github.com/MarshallOfSound/electron-devtools-installer)
|
||||||
|
* [Electron Mocha](https://github.com/jprichardson/electron-mocha)
|
||||||
|
* [Browsersync](https://browsersync.io/)
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
Clone the repository
|
||||||
|
```bash
|
||||||
|
git clone --depth=1 git@github.com:jschr/electron-react-redux-boilerplate.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Install dependencies
|
||||||
|
```bash
|
||||||
|
cd electron-react-redux-boilerplate
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
Development
|
||||||
|
```bash
|
||||||
|
npm run develop
|
||||||
|
```
|
||||||
|
|
||||||
|
## DevTools
|
||||||
|
|
||||||
|
Toggle DevTools:
|
||||||
|
|
||||||
|
* macOS: <kbd>Cmd</kbd> <kbd>Alt</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||||
|
* Linux: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||||
|
* Windows: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>I</kbd> or <kbd>F12</kbd>
|
||||||
|
|
||||||
|
## Packaging
|
||||||
|
|
||||||
|
Modify [electron-builder.yml](./electron-builder.yml) to edit package info.
|
||||||
|
|
||||||
|
For a full list of options see: https://www.electron.build/configuration/configuration
|
||||||
|
|
||||||
|
Create a package for macOS, Windows or Linux using one of the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run pack:mac
|
||||||
|
npm run pack:win
|
||||||
|
npm run pack:linux
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
- [@jschr](https://github.com/jschr)
|
||||||
|
- [@pronebird](https://github.com/pronebird)
|
||||||
|
|
||||||
|
## Apps using this boilerplate
|
||||||
|
|
||||||
|
- [Mullvad VPN app](https://github.com/mullvad/mullvadvpn-app)
|
||||||
|
- [YouTube Downloader Electron](https://github.com/vanzylv/youtube-downloader-electron)
|
||||||
|
- [Martian: A Websocket test tool](https://github.com/drex44/martian)
|
|
@ -1 +0,0 @@
|
||||||
//ACTIONS
|
|
|
@ -1,46 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>App name here</title>
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
if (!process.env.HOT) {
|
|
||||||
const link = document.createElement("link");
|
|
||||||
link.rel = "stylesheet";
|
|
||||||
link.href = "./dist/style.css";
|
|
||||||
// HACK: Writing the script path should be done with webpack
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(link);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
<script>
|
|
||||||
{
|
|
||||||
const scripts = [];
|
|
||||||
|
|
||||||
// Dynamically insert the DLL script in development env in the
|
|
||||||
// renderer process
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
|
||||||
scripts.push("../dll/renderer.dev.dll.js");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamically insert the bundled app script in the renderer process
|
|
||||||
const port = process.env.PORT || 1212;
|
|
||||||
scripts.push(
|
|
||||||
process.env.HOT
|
|
||||||
? "http://localhost:" + port + "/dist/renderer.dev.js"
|
|
||||||
: "./dist/renderer.prod.js"
|
|
||||||
);
|
|
||||||
|
|
||||||
document.write(
|
|
||||||
scripts
|
|
||||||
.map((script) => `<script defer src="${script}"><\/script>`)
|
|
||||||
.join("")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,11 +0,0 @@
|
||||||
import React, { Component } from "react";
|
|
||||||
|
|
||||||
const Home = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Start typing in components\Home.js</h1>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Home;
|
|
|
@ -1,23 +0,0 @@
|
||||||
import React, { Fragment } from "react";
|
|
||||||
import { render } from "react-dom";
|
|
||||||
import { Provider } from "react-redux";
|
|
||||||
import { createStore } from "redux";
|
|
||||||
import rootReducer from "./reducers";
|
|
||||||
import { AppContainer as ReactHotAppContainer } from "react-hot-loader";
|
|
||||||
import Home from "./components/Home";
|
|
||||||
|
|
||||||
const AppContainer = process.env.PLAIN_HMR ? Fragment : ReactHotAppContainer;
|
|
||||||
|
|
||||||
const store = createStore(
|
|
||||||
rootReducer,
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
|
|
||||||
);
|
|
||||||
|
|
||||||
render(
|
|
||||||
<AppContainer>
|
|
||||||
<Provider store={store}>
|
|
||||||
<Home />
|
|
||||||
</Provider>
|
|
||||||
</AppContainer>,
|
|
||||||
document.getElementById("root")
|
|
||||||
);
|
|
|
@ -1,105 +0,0 @@
|
||||||
/* eslint global-require: off */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module executes inside of electron's main process. You can start
|
|
||||||
* electron renderer process from here and communicate with the other processes
|
|
||||||
* through IPC.
|
|
||||||
*
|
|
||||||
* When running `yarn build` or `yarn build-main`, this file is compiled to
|
|
||||||
* `./app/main.prod.js` using webpack. This gives us some performance wins.
|
|
||||||
*
|
|
||||||
* @flow
|
|
||||||
*/
|
|
||||||
import { app, BrowserWindow } from 'electron';
|
|
||||||
import { autoUpdater } from 'electron-updater';
|
|
||||||
import log from 'electron-log';
|
|
||||||
import MenuBuilder from './menu';
|
|
||||||
|
|
||||||
export default class AppUpdater {
|
|
||||||
constructor() {
|
|
||||||
log.transports.file.level = 'info';
|
|
||||||
autoUpdater.logger = log;
|
|
||||||
autoUpdater.checkForUpdatesAndNotify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mainWindow = null;
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
const sourceMapSupport = require('source-map-support');
|
|
||||||
sourceMapSupport.install();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
process.env.NODE_ENV === 'development' ||
|
|
||||||
process.env.DEBUG_PROD === 'true'
|
|
||||||
) {
|
|
||||||
require('electron-debug')();
|
|
||||||
}
|
|
||||||
|
|
||||||
const installExtensions = async () => {
|
|
||||||
const installer = require('electron-devtools-installer');
|
|
||||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
|
||||||
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
|
|
||||||
|
|
||||||
return Promise.all(
|
|
||||||
extensions.map(name => installer.default(installer[name], forceDownload))
|
|
||||||
).catch(console.log);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add event listeners...
|
|
||||||
*/
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
|
||||||
// Respect the OSX convention of having the application in memory even
|
|
||||||
// after all windows have been closed
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('ready', async () => {
|
|
||||||
if (
|
|
||||||
process.env.NODE_ENV === 'development' ||
|
|
||||||
process.env.DEBUG_PROD === 'true'
|
|
||||||
) {
|
|
||||||
await installExtensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
mainWindow = new BrowserWindow({
|
|
||||||
show: false,
|
|
||||||
width: 1024,
|
|
||||||
height: 728,
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.loadURL(`file://${__dirname}/app.html`);
|
|
||||||
|
|
||||||
// @TODO: Use 'ready-to-show' event
|
|
||||||
// https://github.com/electron/electron/blob/master/docs/api/browser-window.md#using-ready-to-show-event
|
|
||||||
mainWindow.webContents.on('did-finish-load', () => {
|
|
||||||
if (!mainWindow) {
|
|
||||||
throw new Error('"mainWindow" is not defined');
|
|
||||||
}
|
|
||||||
if (process.env.START_MINIMIZED) {
|
|
||||||
mainWindow.minimize();
|
|
||||||
} else {
|
|
||||||
mainWindow.show();
|
|
||||||
mainWindow.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mainWindow.on('closed', () => {
|
|
||||||
mainWindow = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const menuBuilder = new MenuBuilder(mainWindow);
|
|
||||||
menuBuilder.buildMenu();
|
|
||||||
|
|
||||||
// Remove this if your app does not use auto updates
|
|
||||||
// eslint-disable-next-line
|
|
||||||
new AppUpdater();
|
|
||||||
});
|
|
103
Dashboard/app/main/index.js
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import path from 'path';
|
||||||
|
import { app, crashReporter, BrowserWindow, Menu } from 'electron';
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
|
let mainWindow = null;
|
||||||
|
let forceQuit = false;
|
||||||
|
|
||||||
|
const installExtensions = async () => {
|
||||||
|
const installer = require('electron-devtools-installer');
|
||||||
|
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
|
||||||
|
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||||
|
for (const name of extensions) {
|
||||||
|
try {
|
||||||
|
await installer.default(installer[name], forceDownload);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Error installing ${name} extension: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
crashReporter.start({
|
||||||
|
productName: 'YourName',
|
||||||
|
companyName: 'YourCompany',
|
||||||
|
submitURL: 'https://your-domain.com/url-to-submit',
|
||||||
|
uploadToServer: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
// On OS X it is common for applications and their menu bar
|
||||||
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('ready', async () => {
|
||||||
|
if (isDevelopment) {
|
||||||
|
await installExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
width: 1000,
|
||||||
|
height: 800,
|
||||||
|
minWidth: 640,
|
||||||
|
minHeight: 480,
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.loadFile(path.resolve(path.join(__dirname, '../renderer/index.html')));
|
||||||
|
|
||||||
|
// show window once on first load
|
||||||
|
mainWindow.webContents.once('did-finish-load', () => {
|
||||||
|
mainWindow.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.webContents.on('did-finish-load', () => {
|
||||||
|
// Handle window logic properly on macOS:
|
||||||
|
// 1. App should not terminate if window has been closed
|
||||||
|
// 2. Click on icon in dock should re-open the window
|
||||||
|
// 3. ⌘+Q should close the window and quit the app
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
mainWindow.on('close', function (e) {
|
||||||
|
if (!forceQuit) {
|
||||||
|
e.preventDefault();
|
||||||
|
mainWindow.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
mainWindow.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
forceQuit = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mainWindow.on('closed', () => {
|
||||||
|
mainWindow = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDevelopment) {
|
||||||
|
// auto-open dev tools
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
|
||||||
|
// add inspect element on right click menu
|
||||||
|
mainWindow.webContents.on('context-menu', (e, props) => {
|
||||||
|
Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: 'Inspect element',
|
||||||
|
click() {
|
||||||
|
mainWindow.inspectElement(props.x, props.y);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]).popup(mainWindow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,277 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { app, Menu, shell, BrowserWindow } from 'electron';
|
|
||||||
|
|
||||||
export default class MenuBuilder {
|
|
||||||
mainWindow: BrowserWindow;
|
|
||||||
|
|
||||||
constructor(mainWindow: BrowserWindow) {
|
|
||||||
this.mainWindow = mainWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildMenu() {
|
|
||||||
if (
|
|
||||||
process.env.NODE_ENV === 'development' ||
|
|
||||||
process.env.DEBUG_PROD === 'true'
|
|
||||||
) {
|
|
||||||
this.setupDevelopmentEnvironment();
|
|
||||||
}
|
|
||||||
|
|
||||||
const template =
|
|
||||||
process.platform === 'darwin'
|
|
||||||
? this.buildDarwinTemplate()
|
|
||||||
: this.buildDefaultTemplate();
|
|
||||||
|
|
||||||
const menu = Menu.buildFromTemplate(template);
|
|
||||||
Menu.setApplicationMenu(menu);
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
setupDevelopmentEnvironment() {
|
|
||||||
this.mainWindow.openDevTools();
|
|
||||||
this.mainWindow.webContents.on('context-menu', (e, props) => {
|
|
||||||
const { x, y } = props;
|
|
||||||
|
|
||||||
Menu.buildFromTemplate([
|
|
||||||
{
|
|
||||||
label: 'Inspect element',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.inspectElement(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]).popup(this.mainWindow);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDarwinTemplate() {
|
|
||||||
const subMenuAbout = {
|
|
||||||
label: 'Electron',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'About ElectronReact',
|
|
||||||
selector: 'orderFrontStandardAboutPanel:'
|
|
||||||
},
|
|
||||||
{ type: 'separator' },
|
|
||||||
{ label: 'Services', submenu: [] },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{
|
|
||||||
label: 'Hide ElectronReact',
|
|
||||||
accelerator: 'Command+H',
|
|
||||||
selector: 'hide:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hide Others',
|
|
||||||
accelerator: 'Command+Shift+H',
|
|
||||||
selector: 'hideOtherApplications:'
|
|
||||||
},
|
|
||||||
{ label: 'Show All', selector: 'unhideAllApplications:' },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
accelerator: 'Command+Q',
|
|
||||||
click: () => {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const subMenuEdit = {
|
|
||||||
label: 'Edit',
|
|
||||||
submenu: [
|
|
||||||
{ label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' },
|
|
||||||
{ label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{ label: 'Cut', accelerator: 'Command+X', selector: 'cut:' },
|
|
||||||
{ label: 'Copy', accelerator: 'Command+C', selector: 'copy:' },
|
|
||||||
{ label: 'Paste', accelerator: 'Command+V', selector: 'paste:' },
|
|
||||||
{
|
|
||||||
label: 'Select All',
|
|
||||||
accelerator: 'Command+A',
|
|
||||||
selector: 'selectAll:'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const subMenuViewDev = {
|
|
||||||
label: 'View',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
accelerator: 'Command+R',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.webContents.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Full Screen',
|
|
||||||
accelerator: 'Ctrl+Command+F',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
accelerator: 'Alt+Command+I',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const subMenuViewProd = {
|
|
||||||
label: 'View',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Toggle Full Screen',
|
|
||||||
accelerator: 'Ctrl+Command+F',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const subMenuWindow = {
|
|
||||||
label: 'Window',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Minimize',
|
|
||||||
accelerator: 'Command+M',
|
|
||||||
selector: 'performMiniaturize:'
|
|
||||||
},
|
|
||||||
{ label: 'Close', accelerator: 'Command+W', selector: 'performClose:' },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{ label: 'Bring All to Front', selector: 'arrangeInFront:' }
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const subMenuHelp = {
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Learn More',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('http://electron.atom.io');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Documentation',
|
|
||||||
click() {
|
|
||||||
shell.openExternal(
|
|
||||||
'https://github.com/atom/electron/tree/master/docs#readme'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Community Discussions',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('https://discuss.atom.io/c/electron');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Search Issues',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('https://github.com/atom/electron/issues');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const subMenuView =
|
|
||||||
process.env.NODE_ENV === 'development' ? subMenuViewDev : subMenuViewProd;
|
|
||||||
|
|
||||||
return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow, subMenuHelp];
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDefaultTemplate() {
|
|
||||||
const templateDefault = [
|
|
||||||
{
|
|
||||||
label: '&File',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: '&Open',
|
|
||||||
accelerator: 'Ctrl+O'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '&Close',
|
|
||||||
accelerator: 'Ctrl+W',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '&View',
|
|
||||||
submenu:
|
|
||||||
process.env.NODE_ENV === 'development'
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
label: '&Reload',
|
|
||||||
accelerator: 'Ctrl+R',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.webContents.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle &Full Screen',
|
|
||||||
accelerator: 'F11',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.setFullScreen(
|
|
||||||
!this.mainWindow.isFullScreen()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle &Developer Tools',
|
|
||||||
accelerator: 'Alt+Ctrl+I',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
label: 'Toggle &Full Screen',
|
|
||||||
accelerator: 'F11',
|
|
||||||
click: () => {
|
|
||||||
this.mainWindow.setFullScreen(
|
|
||||||
!this.mainWindow.isFullScreen()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Learn More',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('http://electron.atom.io');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Documentation',
|
|
||||||
click() {
|
|
||||||
shell.openExternal(
|
|
||||||
'https://github.com/atom/electron/tree/master/docs#readme'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Community Discussions',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('https://discuss.atom.io/c/electron');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Search Issues',
|
|
||||||
click() {
|
|
||||||
shell.openExternal('https://github.com/atom/electron/issues');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return templateDefault;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"name": "electron-react-boilerplate",
|
|
||||||
"productName": "electron-react-boilerplate",
|
|
||||||
"version": "0.18.0",
|
|
||||||
"description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
|
|
||||||
"main": "./main.prod.js",
|
|
||||||
"author": {
|
|
||||||
"name": "Electron React Boilerplate Maintainers",
|
|
||||||
"email": "electronreactboilerplate@gmail.com",
|
|
||||||
"url": "https://github.com/electron-react-boilerplate"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"electron-rebuild": "node -r ../internals/scripts/BabelRegister.js ../internals/scripts/ElectronRebuild.js",
|
|
||||||
"postinstall": "yarn electron-rebuild"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
//rootReducer
|
|
||||||
import { combineReducers } from "redux";
|
|
||||||
|
|
||||||
const rootReducer = combineReducers({});
|
|
||||||
|
|
||||||
export default rootReducer;
|
|
5
Dashboard/app/renderer/.eslintrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true
|
||||||
|
}
|
||||||
|
}
|
6
Dashboard/app/renderer/actions/user.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { createAction } from 'redux-actions';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
login: createAction('USER_LOGIN'),
|
||||||
|
logout: createAction('USER_LOGOUT'),
|
||||||
|
};
|
28
Dashboard/app/renderer/app.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import { ConnectedRouter } from 'connected-react-router';
|
||||||
|
import { createMemoryHistory } from 'history';
|
||||||
|
import routes from './routes';
|
||||||
|
import configureStore from './store';
|
||||||
|
|
||||||
|
const syncHistoryWithStore = (store, history) => {
|
||||||
|
const { router } = store.getState();
|
||||||
|
if (router && router.location) {
|
||||||
|
history.replace(router.location);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState = {};
|
||||||
|
const routerHistory = createMemoryHistory();
|
||||||
|
const store = configureStore(initialState, routerHistory);
|
||||||
|
syncHistoryWithStore(store, routerHistory);
|
||||||
|
|
||||||
|
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<ConnectedRouter history={routerHistory}>{routes}</ConnectedRouter>
|
||||||
|
</Provider>,
|
||||||
|
rootElement,
|
||||||
|
);
|
24
Dashboard/app/renderer/components/LoggedIn.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
export default class LoggedIn extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
onLogout: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleLogout = () => {
|
||||||
|
this.props.onLogout({
|
||||||
|
username: '',
|
||||||
|
loggedIn: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Logged in as {this.props.user.username}</h2>
|
||||||
|
<button onClick={this.handleLogout}>Logout</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
35
Dashboard/app/renderer/components/Login.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
export default class Login extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
onLogin: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
username: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
handleLogin = () => {
|
||||||
|
this.props.onLogin({
|
||||||
|
username: this.state.username,
|
||||||
|
loggedIn: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = (e) => {
|
||||||
|
this.setState({
|
||||||
|
username: e.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Login</h2>
|
||||||
|
<input onChange={this.handleChange} type="text" value={this.state.username} />
|
||||||
|
<button onClick={this.handleLogin}>Log In</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
21
Dashboard/app/renderer/containers/LoggedInPage.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { push } from 'connected-react-router';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import LoggedIn from '../components/LoggedIn';
|
||||||
|
import userActions from '../actions/user';
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
const user = bindActionCreators(userActions, dispatch);
|
||||||
|
return {
|
||||||
|
onLogout: (data) => {
|
||||||
|
user.logout(data);
|
||||||
|
dispatch(push('/'));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(LoggedIn);
|
21
Dashboard/app/renderer/containers/LoginPage.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { push } from 'connected-react-router';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import Login from '../components/Login';
|
||||||
|
import userActions from '../actions/user';
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
const user = bindActionCreators(userActions, dispatch);
|
||||||
|
return {
|
||||||
|
onLogin: (data) => {
|
||||||
|
user.login(data);
|
||||||
|
dispatch(push('/loggedin'));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Login);
|
11
Dashboard/app/renderer/index.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>My App</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="./app.js" data-container="#app"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
Dashboard/app/renderer/reducers/user.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { handleActions } from 'redux-actions';
|
||||||
|
import actions from '../actions/user';
|
||||||
|
|
||||||
|
export default handleActions(
|
||||||
|
{
|
||||||
|
[actions.login]: (state, action) => {
|
||||||
|
return { ...state, ...action.payload };
|
||||||
|
},
|
||||||
|
[actions.logout]: (state, action) => {
|
||||||
|
return { ...state, ...action.payload };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
12
Dashboard/app/renderer/routes.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Switch, Route } from 'react-router';
|
||||||
|
|
||||||
|
import LoginPage from './containers/LoginPage';
|
||||||
|
import LoggedInPage from './containers/LoggedInPage';
|
||||||
|
|
||||||
|
export default (
|
||||||
|
<Switch>
|
||||||
|
<Route exact path="/" component={LoginPage} />
|
||||||
|
<Route exact path="/loggedin" component={LoggedInPage} />
|
||||||
|
</Switch>
|
||||||
|
);
|
36
Dashboard/app/renderer/store.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
|
||||||
|
import { connectRouter, routerMiddleware, push } from 'connected-react-router';
|
||||||
|
import persistState from 'redux-localstorage';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
|
||||||
|
import user from './reducers/user';
|
||||||
|
import userActions from './actions/user';
|
||||||
|
|
||||||
|
export default function configureStore(initialState, routerHistory) {
|
||||||
|
const router = routerMiddleware(routerHistory);
|
||||||
|
|
||||||
|
const actionCreators = {
|
||||||
|
...userActions,
|
||||||
|
push,
|
||||||
|
};
|
||||||
|
|
||||||
|
const reducers = {
|
||||||
|
router: connectRouter(routerHistory),
|
||||||
|
user,
|
||||||
|
};
|
||||||
|
|
||||||
|
const middlewares = [thunk, router];
|
||||||
|
|
||||||
|
const composeEnhancers = (() => {
|
||||||
|
const compose_ = window && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||||
|
if (process.env.NODE_ENV === 'development' && compose_) {
|
||||||
|
return compose_({ actionCreators });
|
||||||
|
}
|
||||||
|
return compose;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const enhancer = composeEnhancers(applyMiddleware(...middlewares), persistState());
|
||||||
|
const rootReducer = combineReducers(reducers);
|
||||||
|
|
||||||
|
return createStore(rootReducer, initialState, enhancer);
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
|
@ -1,66 +1,17 @@
|
||||||
/* eslint global-require: off */
|
module.exports = {
|
||||||
|
presets: [
|
||||||
const developmentEnvironments = ['development', 'test'];
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
const developmentPlugins = [require('react-hot-loader/babel')];
|
{
|
||||||
|
targets: {
|
||||||
const productionPlugins = [
|
electron: '6.0',
|
||||||
require('babel-plugin-dev-expression'),
|
},
|
||||||
|
},
|
||||||
// babel-preset-react-optimize
|
|
||||||
require('@babel/plugin-transform-react-constant-elements'),
|
|
||||||
require('@babel/plugin-transform-react-inline-elements'),
|
|
||||||
require('babel-plugin-transform-react-remove-prop-types')
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = api => {
|
|
||||||
// see docs about api at https://babeljs.io/docs/en/config-files#apicache
|
|
||||||
|
|
||||||
const development = api.env(developmentEnvironments);
|
|
||||||
|
|
||||||
return {
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
require('@babel/preset-env'),
|
|
||||||
{
|
|
||||||
targets: { electron: require('electron/package.json').version }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
require('@babel/preset-flow'),
|
|
||||||
[require('@babel/preset-react'), { development }]
|
|
||||||
],
|
],
|
||||||
plugins: [
|
'@babel/preset-react',
|
||||||
// Stage 0
|
],
|
||||||
require('@babel/plugin-proposal-function-bind'),
|
plugins: [
|
||||||
|
['@babel/plugin-proposal-decorators', { legacy: true }],
|
||||||
// Stage 1
|
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||||
require('@babel/plugin-proposal-export-default-from'),
|
],
|
||||||
require('@babel/plugin-proposal-logical-assignment-operators'),
|
|
||||||
[require('@babel/plugin-proposal-optional-chaining'), { loose: false }],
|
|
||||||
[
|
|
||||||
require('@babel/plugin-proposal-pipeline-operator'),
|
|
||||||
{ proposal: 'minimal' }
|
|
||||||
],
|
|
||||||
[
|
|
||||||
require('@babel/plugin-proposal-nullish-coalescing-operator'),
|
|
||||||
{ loose: false }
|
|
||||||
],
|
|
||||||
require('@babel/plugin-proposal-do-expressions'),
|
|
||||||
|
|
||||||
// Stage 2
|
|
||||||
[require('@babel/plugin-proposal-decorators'), { legacy: true }],
|
|
||||||
require('@babel/plugin-proposal-function-sent'),
|
|
||||||
require('@babel/plugin-proposal-export-namespace-from'),
|
|
||||||
require('@babel/plugin-proposal-numeric-separator'),
|
|
||||||
require('@babel/plugin-proposal-throw-expressions'),
|
|
||||||
|
|
||||||
// Stage 3
|
|
||||||
require('@babel/plugin-syntax-dynamic-import'),
|
|
||||||
require('@babel/plugin-syntax-import-meta'),
|
|
||||||
[require('@babel/plugin-proposal-class-properties'), { loose: true }],
|
|
||||||
require('@babel/plugin-proposal-json-strings'),
|
|
||||||
|
|
||||||
...(development ? developmentPlugins : productionPlugins)
|
|
||||||
]
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
/**
|
|
||||||
* Base webpack config used across other specific configs
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import webpack from 'webpack';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { dependencies as externals } from '../app/package.json';
|
|
||||||
import { dependencies as possibleExternals } from '../package.json';
|
|
||||||
|
|
||||||
// Find all the dependencies without a `main` property and add them as webpack externals
|
|
||||||
function filterDepWithoutEntryPoints(dep: string): boolean {
|
|
||||||
// Return true if we want to add a dependency to externals
|
|
||||||
try {
|
|
||||||
// If the root of the dependency has an index.js, return true
|
|
||||||
if (
|
|
||||||
fs.existsSync(path.join(__dirname, '..', `node_modules/${dep}/index.js`))
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const pgkString = fs
|
|
||||||
.readFileSync(require.resolve(`${dep}/package`))
|
|
||||||
.toString();
|
|
||||||
const pkg = JSON.parse(pgkString);
|
|
||||||
const fields = ['main', 'module', 'jsnext:main', 'browser'];
|
|
||||||
return !fields.some(field => field in pkg);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
externals: [
|
|
||||||
...Object.keys(externals || {}),
|
|
||||||
...Object.keys(possibleExternals || {}).filter(filterDepWithoutEntryPoints)
|
|
||||||
],
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, '..', 'app'),
|
|
||||||
// https://github.com/webpack/webpack/issues/1114
|
|
||||||
libraryTarget: 'commonjs2'
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the array of extensions that should be used to resolve modules.
|
|
||||||
*/
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.js', '.jsx', '.json'],
|
|
||||||
modules: [path.join(__dirname, '..', 'app'), 'node_modules']
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.EnvironmentPlugin({
|
|
||||||
NODE_ENV: 'production'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.NamedModulesPlugin()
|
|
||||||
]
|
|
||||||
};
|
|
|
@ -1,4 +0,0 @@
|
||||||
/* eslint import/no-unresolved: off, import/no-self-import: off */
|
|
||||||
require('@babel/register');
|
|
||||||
|
|
||||||
module.exports = require('./webpack.config.renderer.dev.babel').default;
|
|
|
@ -1,73 +0,0 @@
|
||||||
/**
|
|
||||||
* Webpack config for production electron main process
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import webpack from 'webpack';
|
|
||||||
import merge from 'webpack-merge';
|
|
||||||
import TerserPlugin from 'terser-webpack-plugin';
|
|
||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
||||||
import baseConfig from './webpack.config.base';
|
|
||||||
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
|
|
||||||
|
|
||||||
CheckNodeEnv('production');
|
|
||||||
|
|
||||||
export default merge.smart(baseConfig, {
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
mode: 'production',
|
|
||||||
|
|
||||||
target: 'electron-main',
|
|
||||||
|
|
||||||
entry: './app/main.dev',
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, '..'),
|
|
||||||
filename: './app/main.prod.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
minimizer: process.env.E2E_BUILD
|
|
||||||
? []
|
|
||||||
: [
|
|
||||||
new TerserPlugin({
|
|
||||||
parallel: true,
|
|
||||||
sourceMap: true,
|
|
||||||
cache: true
|
|
||||||
})
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new BundleAnalyzerPlugin({
|
|
||||||
analyzerMode:
|
|
||||||
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
|
|
||||||
openAnalyzer: process.env.OPEN_ANALYZER === 'true'
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create global constants which can be configured at compile time.
|
|
||||||
*
|
|
||||||
* Useful for allowing different behaviour between development builds and
|
|
||||||
* release builds
|
|
||||||
*
|
|
||||||
* NODE_ENV should be production so that modules do not perform certain
|
|
||||||
* development checks
|
|
||||||
*/
|
|
||||||
new webpack.EnvironmentPlugin({
|
|
||||||
NODE_ENV: 'production',
|
|
||||||
DEBUG_PROD: false,
|
|
||||||
START_MINIMIZED: false
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables webpack processing of __dirname and __filename.
|
|
||||||
* If you run the bundle in node.js it falls back to these values of node.js.
|
|
||||||
* https://github.com/webpack/webpack/issues/2010
|
|
||||||
*/
|
|
||||||
node: {
|
|
||||||
__dirname: false,
|
|
||||||
__filename: false
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,279 +0,0 @@
|
||||||
/* eslint global-require: off, import/no-dynamic-require: off */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build config for development electron renderer process that uses
|
|
||||||
* Hot-Module-Replacement
|
|
||||||
*
|
|
||||||
* https://webpack.js.org/concepts/hot-module-replacement/
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import webpack from 'webpack';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import merge from 'webpack-merge';
|
|
||||||
import { spawn, execSync } from 'child_process';
|
|
||||||
import baseConfig from './webpack.config.base';
|
|
||||||
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
|
|
||||||
|
|
||||||
CheckNodeEnv('development');
|
|
||||||
|
|
||||||
const port = process.env.PORT || 1212;
|
|
||||||
const publicPath = `http://localhost:${port}/dist`;
|
|
||||||
const dll = path.join(__dirname, '..', 'dll');
|
|
||||||
const manifest = path.resolve(dll, 'renderer.json');
|
|
||||||
const requiredByDLLConfig = module.parent.filename.includes(
|
|
||||||
'webpack.config.renderer.dev.dll'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warn if the DLL is not built
|
|
||||||
*/
|
|
||||||
if (!requiredByDLLConfig && !(fs.existsSync(dll) && fs.existsSync(manifest))) {
|
|
||||||
console.log(
|
|
||||||
chalk.black.bgYellow.bold(
|
|
||||||
'The DLL files are missing. Sit back while we build them for you with "yarn build-dll"'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
execSync('yarn build-dll');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default merge.smart(baseConfig, {
|
|
||||||
devtool: 'inline-source-map',
|
|
||||||
|
|
||||||
mode: 'development',
|
|
||||||
|
|
||||||
target: 'electron-renderer',
|
|
||||||
|
|
||||||
entry: [
|
|
||||||
...(process.env.PLAIN_HMR ? [] : ['react-hot-loader/patch']),
|
|
||||||
`webpack-dev-server/client?http://localhost:${port}/`,
|
|
||||||
'webpack/hot/only-dev-server',
|
|
||||||
require.resolve('../app/index')
|
|
||||||
],
|
|
||||||
|
|
||||||
output: {
|
|
||||||
publicPath: `http://localhost:${port}/dist/`,
|
|
||||||
filename: 'renderer.dev.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.global\.css$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /^((?!\.global).)*\.css$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]__[local]__[hash:base64:5]'
|
|
||||||
},
|
|
||||||
sourceMap: true,
|
|
||||||
importLoaders: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// SASS support - compile all .global.scss files and pipe it to style.css
|
|
||||||
{
|
|
||||||
test: /\.global\.(scss|sass)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// SASS support - compile all other .scss files and pipe it to style.css
|
|
||||||
{
|
|
||||||
test: /^((?!\.global).)*\.(scss|sass)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]__[local]__[hash:base64:5]'
|
|
||||||
},
|
|
||||||
sourceMap: true,
|
|
||||||
importLoaders: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// WOFF Font
|
|
||||||
{
|
|
||||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/font-woff'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// WOFF2 Font
|
|
||||||
{
|
|
||||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/font-woff'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// TTF Font
|
|
||||||
{
|
|
||||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/octet-stream'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// EOT Font
|
|
||||||
{
|
|
||||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: 'file-loader'
|
|
||||||
},
|
|
||||||
// SVG Font
|
|
||||||
{
|
|
||||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'image/svg+xml'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Common Image Formats
|
|
||||||
{
|
|
||||||
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
|
|
||||||
use: 'url-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'react-dom': '@hot-loader/react-dom'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
requiredByDLLConfig
|
|
||||||
? null
|
|
||||||
: new webpack.DllReferencePlugin({
|
|
||||||
context: path.join(__dirname, '..', 'dll'),
|
|
||||||
manifest: require(manifest),
|
|
||||||
sourceType: 'var'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.HotModuleReplacementPlugin({
|
|
||||||
multiStep: true
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.NoEmitOnErrorsPlugin(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create global constants which can be configured at compile time.
|
|
||||||
*
|
|
||||||
* Useful for allowing different behaviour between development builds and
|
|
||||||
* release builds
|
|
||||||
*
|
|
||||||
* NODE_ENV should be production so that modules do not perform certain
|
|
||||||
* development checks
|
|
||||||
*
|
|
||||||
* By default, use 'development' as NODE_ENV. This can be overriden with
|
|
||||||
* 'staging', for example, by changing the ENV variables in the npm scripts
|
|
||||||
*/
|
|
||||||
new webpack.EnvironmentPlugin({
|
|
||||||
NODE_ENV: 'development'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
debug: true
|
|
||||||
})
|
|
||||||
],
|
|
||||||
|
|
||||||
node: {
|
|
||||||
__dirname: false,
|
|
||||||
__filename: false
|
|
||||||
},
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
port,
|
|
||||||
publicPath,
|
|
||||||
compress: true,
|
|
||||||
noInfo: true,
|
|
||||||
stats: 'errors-only',
|
|
||||||
inline: true,
|
|
||||||
lazy: false,
|
|
||||||
hot: true,
|
|
||||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
|
||||||
contentBase: path.join(__dirname, 'dist'),
|
|
||||||
watchOptions: {
|
|
||||||
aggregateTimeout: 300,
|
|
||||||
ignored: /node_modules/,
|
|
||||||
poll: 100
|
|
||||||
},
|
|
||||||
historyApiFallback: {
|
|
||||||
verbose: true,
|
|
||||||
disableDotRule: false
|
|
||||||
},
|
|
||||||
before() {
|
|
||||||
if (process.env.START_HOT) {
|
|
||||||
console.log('Starting Main Process...');
|
|
||||||
spawn('npm', ['run', 'start-main-dev'], {
|
|
||||||
shell: true,
|
|
||||||
env: process.env,
|
|
||||||
stdio: 'inherit'
|
|
||||||
})
|
|
||||||
.on('close', code => process.exit(code))
|
|
||||||
.on('error', spawnError => console.error(spawnError));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,74 +0,0 @@
|
||||||
/* eslint global-require: off, import/no-dynamic-require: off */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the DLL for development electron renderer process
|
|
||||||
*/
|
|
||||||
|
|
||||||
import webpack from 'webpack';
|
|
||||||
import path from 'path';
|
|
||||||
import merge from 'webpack-merge';
|
|
||||||
import baseConfig from './webpack.config.base';
|
|
||||||
import { dependencies } from '../package.json';
|
|
||||||
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
|
|
||||||
|
|
||||||
CheckNodeEnv('development');
|
|
||||||
|
|
||||||
const dist = path.join(__dirname, '..', 'dll');
|
|
||||||
|
|
||||||
export default merge.smart(baseConfig, {
|
|
||||||
context: path.join(__dirname, '..'),
|
|
||||||
|
|
||||||
devtool: 'eval',
|
|
||||||
|
|
||||||
mode: 'development',
|
|
||||||
|
|
||||||
target: 'electron-renderer',
|
|
||||||
|
|
||||||
externals: ['fsevents', 'crypto-browserify'],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use `module` from `webpack.config.renderer.dev.js`
|
|
||||||
*/
|
|
||||||
module: require('./webpack.config.renderer.dev.babel').default.module,
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
renderer: Object.keys(dependencies || {})
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
library: 'renderer',
|
|
||||||
path: dist,
|
|
||||||
filename: '[name].dev.dll.js',
|
|
||||||
libraryTarget: 'var'
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.DllPlugin({
|
|
||||||
path: path.join(dist, '[name].json'),
|
|
||||||
name: '[name]'
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create global constants which can be configured at compile time.
|
|
||||||
*
|
|
||||||
* Useful for allowing different behaviour between development builds and
|
|
||||||
* release builds
|
|
||||||
*
|
|
||||||
* NODE_ENV should be production so that modules do not perform certain
|
|
||||||
* development checks
|
|
||||||
*/
|
|
||||||
new webpack.EnvironmentPlugin({
|
|
||||||
NODE_ENV: 'development'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
debug: true,
|
|
||||||
options: {
|
|
||||||
context: path.join(__dirname, '..', 'app'),
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, '..', 'dll')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
|
@ -1,218 +0,0 @@
|
||||||
/**
|
|
||||||
* Build config for electron renderer process
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import webpack from 'webpack';
|
|
||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
|
||||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
|
||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
||||||
import merge from 'webpack-merge';
|
|
||||||
import TerserPlugin from 'terser-webpack-plugin';
|
|
||||||
import baseConfig from './webpack.config.base';
|
|
||||||
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
|
|
||||||
|
|
||||||
CheckNodeEnv('production');
|
|
||||||
|
|
||||||
export default merge.smart(baseConfig, {
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
mode: 'production',
|
|
||||||
|
|
||||||
target: 'electron-renderer',
|
|
||||||
|
|
||||||
entry: path.join(__dirname, '..', 'app/index'),
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, '..', 'app/dist'),
|
|
||||||
publicPath: './dist/',
|
|
||||||
filename: 'renderer.prod.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
// Extract all .global.css to style.css as is
|
|
||||||
{
|
|
||||||
test: /\.global\.css$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: MiniCssExtractPlugin.loader,
|
|
||||||
options: {
|
|
||||||
publicPath: './'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// Pipe other styles through css modules and append to style.css
|
|
||||||
{
|
|
||||||
test: /^((?!\.global).)*\.css$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: MiniCssExtractPlugin.loader
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]__[local]__[hash:base64:5]'
|
|
||||||
},
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// Add SASS support - compile all .global.scss files and pipe it to style.css
|
|
||||||
{
|
|
||||||
test: /\.global\.(scss|sass)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: MiniCssExtractPlugin.loader
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
importLoaders: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// Add SASS support - compile all other .scss files and pipe it to style.css
|
|
||||||
{
|
|
||||||
test: /^((?!\.global).)*\.(scss|sass)$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: MiniCssExtractPlugin.loader
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]__[local]__[hash:base64:5]'
|
|
||||||
},
|
|
||||||
importLoaders: 1,
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// WOFF Font
|
|
||||||
{
|
|
||||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/font-woff'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// WOFF2 Font
|
|
||||||
{
|
|
||||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/font-woff'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// TTF Font
|
|
||||||
{
|
|
||||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'application/octet-stream'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// EOT Font
|
|
||||||
{
|
|
||||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: 'file-loader'
|
|
||||||
},
|
|
||||||
// SVG Font
|
|
||||||
{
|
|
||||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
mimetype: 'image/svg+xml'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Common Image Formats
|
|
||||||
{
|
|
||||||
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
|
|
||||||
use: 'url-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
minimizer: process.env.E2E_BUILD
|
|
||||||
? []
|
|
||||||
: [
|
|
||||||
new TerserPlugin({
|
|
||||||
parallel: true,
|
|
||||||
sourceMap: true,
|
|
||||||
cache: true
|
|
||||||
}),
|
|
||||||
new OptimizeCSSAssetsPlugin({
|
|
||||||
cssProcessorOptions: {
|
|
||||||
map: {
|
|
||||||
inline: false,
|
|
||||||
annotation: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
/**
|
|
||||||
* Create global constants which can be configured at compile time.
|
|
||||||
*
|
|
||||||
* Useful for allowing different behaviour between development builds and
|
|
||||||
* release builds
|
|
||||||
*
|
|
||||||
* NODE_ENV should be production so that modules do not perform certain
|
|
||||||
* development checks
|
|
||||||
*/
|
|
||||||
new webpack.EnvironmentPlugin({
|
|
||||||
NODE_ENV: 'production'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: 'style.css'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new BundleAnalyzerPlugin({
|
|
||||||
analyzerMode:
|
|
||||||
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
|
|
||||||
openAnalyzer: process.env.OPEN_ANALYZER === 'true'
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
0
Dashboard/dist-assets/.gitkeep
Normal file
37
Dashboard/electron-builder.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
appId: com.example.app
|
||||||
|
copyright: Example co
|
||||||
|
productName: MyApp
|
||||||
|
|
||||||
|
asar: true
|
||||||
|
|
||||||
|
directories:
|
||||||
|
buildResources: dist-assets/
|
||||||
|
output: dist/
|
||||||
|
|
||||||
|
files:
|
||||||
|
- package.json
|
||||||
|
- init.js
|
||||||
|
- build/
|
||||||
|
- node_modules/
|
||||||
|
|
||||||
|
dmg:
|
||||||
|
contents:
|
||||||
|
- type: link
|
||||||
|
path: /Applications
|
||||||
|
x: 410
|
||||||
|
y: 150
|
||||||
|
- type: file
|
||||||
|
x: 130
|
||||||
|
y: 150
|
||||||
|
|
||||||
|
mac:
|
||||||
|
target: dmg
|
||||||
|
category: public.app-category.tools
|
||||||
|
|
||||||
|
win:
|
||||||
|
target: nsis
|
||||||
|
|
||||||
|
linux:
|
||||||
|
target:
|
||||||
|
- deb
|
||||||
|
- AppImage
|
3
Dashboard/flow-typed/module_vx.x.x.js
vendored
|
@ -1,3 +0,0 @@
|
||||||
declare module 'module' {
|
|
||||||
declare module.exports: any;
|
|
||||||
}
|
|
16
Dashboard/gulpfile.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const { task, series } = require('gulp');
|
||||||
|
const rimraf = require('rimraf');
|
||||||
|
|
||||||
|
const scripts = require('./tasks/scripts');
|
||||||
|
const assets = require('./tasks/assets');
|
||||||
|
const watch = require('./tasks/watch');
|
||||||
|
const dist = require('./tasks/distribution');
|
||||||
|
|
||||||
|
task('clean', function (done) {
|
||||||
|
rimraf('./build', done);
|
||||||
|
});
|
||||||
|
task('build', series('clean', assets.copyHtml, scripts.build));
|
||||||
|
task('develop', series('clean', watch.start));
|
||||||
|
task('pack-win', series('build', dist.packWin));
|
||||||
|
task('pack-linux', series('build', dist.packLinux));
|
||||||
|
task('pack-mac', series('build', dist.packMac));
|
1
Dashboard/init.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
require('./build/main');
|
|
@ -1,3 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
declare export default { [key: string]: string }
|
|
|
@ -1,2 +0,0 @@
|
||||||
// @flow
|
|
||||||
declare export default string
|
|
|
@ -1 +0,0 @@
|
||||||
export default 'test-file-stub';
|
|
|
@ -1,5 +0,0 @@
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
require('@babel/register')({
|
|
||||||
cwd: path.join(__dirname, '..', '..')
|
|
||||||
});
|
|
|
@ -1,35 +0,0 @@
|
||||||
// @flow
|
|
||||||
// Check if the renderer and main bundles are built
|
|
||||||
import path from 'path';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
function CheckBuildsExist() {
|
|
||||||
const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js');
|
|
||||||
const rendererPath = path.join(
|
|
||||||
__dirname,
|
|
||||||
'..',
|
|
||||||
'..',
|
|
||||||
'app',
|
|
||||||
'dist',
|
|
||||||
'renderer.prod.js'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!fs.existsSync(mainPath)) {
|
|
||||||
throw new Error(
|
|
||||||
chalk.whiteBright.bgRed.bold(
|
|
||||||
'The main process is not built yet. Build it by running "yarn build-main"'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.existsSync(rendererPath)) {
|
|
||||||
throw new Error(
|
|
||||||
chalk.whiteBright.bgRed.bold(
|
|
||||||
'The renderer process is not built yet. Build it by running "yarn build-renderer"'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBuildsExist();
|
|
|
@ -1,51 +0,0 @@
|
||||||
// @flow
|
|
||||||
import fs from 'fs';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
import { dependencies } from '../../package';
|
|
||||||
|
|
||||||
(() => {
|
|
||||||
if (!dependencies) return;
|
|
||||||
const dependenciesKeys = Object.keys(dependencies);
|
|
||||||
const nativeDeps = fs
|
|
||||||
.readdirSync('node_modules')
|
|
||||||
.filter(folder => fs.existsSync(`node_modules/${folder}/binding.gyp`));
|
|
||||||
try {
|
|
||||||
// Find the reason for why the dependency is installed. If it is installed
|
|
||||||
// because of a devDependency then that is okay. Warn when it is installed
|
|
||||||
// because of a dependency
|
|
||||||
const { dependencies: dependenciesObject } = JSON.parse(
|
|
||||||
execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
|
|
||||||
);
|
|
||||||
const rootDependencies = Object.keys(dependenciesObject);
|
|
||||||
const filteredRootDependencies = rootDependencies.filter(rootDependency =>
|
|
||||||
dependenciesKeys.includes(rootDependency)
|
|
||||||
);
|
|
||||||
if (filteredRootDependencies.length > 0) {
|
|
||||||
const plural = filteredRootDependencies.length > 1;
|
|
||||||
console.log(`
|
|
||||||
${chalk.whiteBright.bgYellow.bold(
|
|
||||||
'Webpack does not work with native dependencies.'
|
|
||||||
)}
|
|
||||||
${chalk.bold(filteredRootDependencies.join(', '))} ${
|
|
||||||
plural ? 'are native dependencies' : 'is a native dependency'
|
|
||||||
} and should be installed inside of the "./app" folder.
|
|
||||||
First uninstall the packages from "./package.json":
|
|
||||||
${chalk.whiteBright.bgGreen.bold('yarn remove your-package')}
|
|
||||||
${chalk.bold(
|
|
||||||
'Then, instead of installing the package to the root "./package.json":'
|
|
||||||
)}
|
|
||||||
${chalk.whiteBright.bgRed.bold('yarn add your-package')}
|
|
||||||
${chalk.bold('Install the package to "./app/package.json"')}
|
|
||||||
${chalk.whiteBright.bgGreen.bold('cd ./app && yarn add your-package')}
|
|
||||||
Read more about native dependencies at:
|
|
||||||
${chalk.bold(
|
|
||||||
'https://github.com/electron-react-boilerplate/electron-react-boilerplate/wiki/Module-Structure----Two-package.json-Structure'
|
|
||||||
)}
|
|
||||||
`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Native dependencies could not be checked');
|
|
||||||
}
|
|
||||||
})();
|
|
|
@ -1,17 +0,0 @@
|
||||||
// @flow
|
|
||||||
import chalk from 'chalk';
|
|
||||||
|
|
||||||
export default function CheckNodeEnv(expectedEnv: string) {
|
|
||||||
if (!expectedEnv) {
|
|
||||||
throw new Error('"expectedEnv" not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== expectedEnv) {
|
|
||||||
console.log(
|
|
||||||
chalk.whiteBright.bgRed.bold(
|
|
||||||
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// @flow
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import detectPort from 'detect-port';
|
|
||||||
|
|
||||||
(function CheckPortInUse() {
|
|
||||||
const port: string = process.env.PORT || '1212';
|
|
||||||
|
|
||||||
detectPort(port, (err: ?Error, availablePort: number) => {
|
|
||||||
if (port !== String(availablePort)) {
|
|
||||||
throw new Error(
|
|
||||||
chalk.whiteBright.bgRed.bold(
|
|
||||||
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 yarn dev`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
|
@ -1,7 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
|
|
||||||
console.warn(
|
|
||||||
"\u001b[33mYou don't seem to be using yarn. This could produce unexpected results.\u001b[39m"
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// @flow
|
|
||||||
import path from 'path';
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { dependencies } from '../../app/package';
|
|
||||||
|
|
||||||
(() => {
|
|
||||||
const nodeModulesPath = path.join(
|
|
||||||
__dirname,
|
|
||||||
'..',
|
|
||||||
'..',
|
|
||||||
'app',
|
|
||||||
'node_modules'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
Object.keys(dependencies || {}).length > 0 &&
|
|
||||||
fs.existsSync(nodeModulesPath)
|
|
||||||
) {
|
|
||||||
const electronRebuildCmd =
|
|
||||||
'../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .';
|
|
||||||
const cmd =
|
|
||||||
process.platform === 'win32'
|
|
||||||
? electronRebuildCmd.replace(/\//g, '\\')
|
|
||||||
: electronRebuildCmd;
|
|
||||||
execSync(cmd, {
|
|
||||||
cwd: path.join(__dirname, '..', '..', 'app'),
|
|
||||||
stdio: 'inherit'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
12562
Dashboard/package-lock.json
generated
Normal file
|
@ -1,255 +1,62 @@
|
||||||
{
|
{
|
||||||
"name": "electron-react-boilerplate",
|
"name": "electron-react-redux-boilerplate",
|
||||||
"productName": "AppNameHere",
|
"version": "0.0.0",
|
||||||
"version": "0.18.0",
|
"description": "electron-react-redux-boilerplate",
|
||||||
"description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
|
"main": "init.js",
|
||||||
"build": {
|
|
||||||
"productName": "AppNameHere",
|
|
||||||
"appId": "org.develar.AppNameHere",
|
|
||||||
"files": [
|
|
||||||
"dist/",
|
|
||||||
"node_modules/",
|
|
||||||
"app.html",
|
|
||||||
"main.prod.js",
|
|
||||||
"main.prod.js.map",
|
|
||||||
"package.json"
|
|
||||||
],
|
|
||||||
"dmg": {
|
|
||||||
"contents": [
|
|
||||||
{
|
|
||||||
"x": 130,
|
|
||||||
"y": 220
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": 410,
|
|
||||||
"y": 220,
|
|
||||||
"type": "link",
|
|
||||||
"path": "/Applications"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"win": {
|
|
||||||
"target": [
|
|
||||||
"nsis",
|
|
||||||
"msi"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"linux": {
|
|
||||||
"target": [
|
|
||||||
"deb",
|
|
||||||
"rpm",
|
|
||||||
"AppImage"
|
|
||||||
],
|
|
||||||
"category": "Development"
|
|
||||||
},
|
|
||||||
"directories": {
|
|
||||||
"buildResources": "resources",
|
|
||||||
"output": "release"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "concurrently \"yarn build-main\" \"yarn build-renderer\"",
|
|
||||||
"build-dll": "cross-env NODE_ENV=development webpack --config ./configs/webpack.config.renderer.dev.dll.babel.js --colors",
|
|
||||||
"build-e2e": "cross-env E2E_BUILD=true yarn build",
|
|
||||||
"build-main": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.main.prod.babel.js --colors",
|
|
||||||
"build-renderer": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
|
|
||||||
"dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && cross-env START_HOT=1 yarn start-renderer-dev",
|
|
||||||
"electron-rebuild": "electron-rebuild --parallel --force --types prod,dev,optional --module-dir app",
|
|
||||||
"flow": "flow",
|
|
||||||
"flow-typed": "rimraf flow-typed/npm && flow-typed install --overwrite || true",
|
|
||||||
"lint": "cross-env NODE_ENV=development eslint --cache --format=pretty .",
|
|
||||||
"lint-fix": "yarn --silent lint --fix; exit 0",
|
|
||||||
"lint-styles": "stylelint --ignore-path .eslintignore '**/*.*(css|scss)' --syntax scss",
|
|
||||||
"lint-styles-fix": "yarn --silent lint-styles --fix; exit 0",
|
|
||||||
"package": "yarn build && electron-builder build --publish never",
|
|
||||||
"package-all": "yarn build && electron-builder build -mwl",
|
|
||||||
"package-ci": "yarn postinstall && yarn build && electron-builder --publish always",
|
|
||||||
"package-linux": "yarn build && electron-builder build --linux",
|
|
||||||
"package-win": "yarn build && electron-builder build --win --x64",
|
|
||||||
"postinstall": "node -r @babel/register internals/scripts/CheckNativeDep.js && yarn flow-typed && electron-builder install-app-deps && yarn build-dll && opencollective-postinstall",
|
|
||||||
"postlint-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{js,jsx,json,html,css,less,scss,yml}'",
|
|
||||||
"postlint-styles-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{css,scss}'",
|
|
||||||
"preinstall": "node ./internals/scripts/CheckYarn.js",
|
|
||||||
"prestart": "yarn build",
|
|
||||||
"start": "cross-env NODE_ENV=production electron ./app/main.prod.js",
|
|
||||||
"start-main-dev": "cross-env HOT=1 NODE_ENV=development electron -r @babel/register ./app/main.dev.js",
|
|
||||||
"start-renderer-dev": "cross-env NODE_ENV=development webpack-dev-server --config configs/webpack.config.renderer.dev.babel.js",
|
|
||||||
"test": "cross-env NODE_ENV=test BABEL_DISABLE_CACHE=1 jest",
|
|
||||||
"test-all": "yarn lint && yarn flow && yarn build && yarn test && yarn build-e2e && yarn test-e2e",
|
|
||||||
"test-e2e": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe electron:./app ./test/e2e/HomePage.e2e.js",
|
|
||||||
"test-e2e-live": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe-live electron:./app ./test/e2e/HomePage.e2e.js",
|
|
||||||
"test-watch": "yarn test --watch"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,jsx}": [
|
|
||||||
"cross-env NODE_ENV=development eslint --cache --format=pretty",
|
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"{*.json,.{babelrc,eslintrc,prettierrc,stylelintrc}}": [
|
|
||||||
"prettier --ignore-path .eslintignore --parser json --write",
|
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"*.{css,scss}": [
|
|
||||||
"stylelint --ignore-path .eslintignore --syntax scss --fix",
|
|
||||||
"prettier --ignore-path .eslintignore --single-quote --write",
|
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"*.{html,md,yml}": [
|
|
||||||
"prettier --ignore-path .eslintignore --single-quote --write",
|
|
||||||
"git add"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/GHOSCHT/electron-react-boilerplate.git"
|
|
||||||
},
|
|
||||||
"author": {
|
"author": {
|
||||||
"name": "GHOSCHT",
|
"name": "Jordan Schroter",
|
||||||
"url": "https://github.com/GHOSCHT"
|
"email": "email@author.com"
|
||||||
},
|
},
|
||||||
|
"repository": "https://github.com/jschr/electron-react-redux-boilerplate",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"jest": {
|
"dependencies": {
|
||||||
"testURL": "http://localhost/",
|
"@babel/register": "^7.9.0",
|
||||||
"moduleNameMapper": {
|
"connected-react-router": "^6.8.0",
|
||||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/fileMock.js",
|
"history": "^4.10.1",
|
||||||
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
|
"prop-types": "^15.7.2",
|
||||||
},
|
"react": "^16.13.1",
|
||||||
"moduleFileExtensions": [
|
"react-dom": "^16.13.0",
|
||||||
"js",
|
"react-redux": "^7.2.0",
|
||||||
"jsx",
|
"react-router": "^5.1.2",
|
||||||
"json"
|
"redux": "^4.0.5",
|
||||||
],
|
"redux-actions": "^2.6.5",
|
||||||
"moduleDirectories": [
|
"redux-localstorage": "^0.4.1",
|
||||||
"node_modules",
|
"redux-thunk": "^2.2.0"
|
||||||
"app/node_modules"
|
|
||||||
],
|
|
||||||
"transform": {
|
|
||||||
"^.+\\.jsx?$": "babel-jest"
|
|
||||||
},
|
|
||||||
"setupFiles": [
|
|
||||||
"./internals/scripts/CheckBuildsExist.js"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.7.2",
|
"@babel/core": "^7.9.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||||
"@babel/plugin-proposal-decorators": "^7.7.0",
|
"@babel/plugin-proposal-decorators": "^7.8.3",
|
||||||
"@babel/plugin-proposal-do-expressions": "^7.6.0",
|
"@babel/preset-env": "^7.9.5",
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.5.2",
|
"@babel/preset-react": "^7.9.4",
|
||||||
"@babel/plugin-proposal-export-namespace-from": "^7.5.2",
|
"babel-eslint": "^10.1.0",
|
||||||
"@babel/plugin-proposal-function-bind": "^7.2.0",
|
"browser-sync": "^2.26.7",
|
||||||
"@babel/plugin-proposal-function-sent": "^7.7.0",
|
"chai": "^4.1.0",
|
||||||
"@babel/plugin-proposal-json-strings": "^7.2.0",
|
"electron": "^8.2.2",
|
||||||
"@babel/plugin-proposal-logical-assignment-operators": "^7.2.0",
|
"electron-builder": "^22.4.1",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.2.0",
|
"electron-devtools-installer": "^3.0.0",
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.2.0",
|
"electron-mocha": "^8.2.1",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.6.0",
|
"eslint": "^6.8.0",
|
||||||
"@babel/plugin-proposal-pipeline-operator": "^7.5.0",
|
"eslint-config-prettier": "^6.10.1",
|
||||||
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
|
"eslint-plugin-react": "^7.19.0",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"gulp": "^4.0.2",
|
||||||
"@babel/plugin-syntax-import-meta": "^7.2.0",
|
"gulp-babel": "^8.0.0",
|
||||||
"@babel/plugin-transform-react-constant-elements": "^7.6.3",
|
"gulp-inject-string": "^1.1.2",
|
||||||
"@babel/plugin-transform-react-inline-elements": "^7.2.0",
|
"gulp-sourcemaps": "^2.6.5",
|
||||||
"@babel/preset-env": "^7.7.1",
|
"prettier": "^2.0.4",
|
||||||
"@babel/preset-flow": "^7.0.0",
|
"redux-mock-store": "^1.5.4",
|
||||||
"@babel/preset-react": "^7.7.0",
|
"rimraf": "^3.0.2"
|
||||||
"@babel/register": "^7.7.0",
|
|
||||||
"babel-core": "7.0.0-bridge.0",
|
|
||||||
"babel-eslint": "^10.0.3",
|
|
||||||
"babel-jest": "^24.9.0",
|
|
||||||
"babel-loader": "^8.0.5",
|
|
||||||
"babel-plugin-dev-expression": "^0.2.2",
|
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
|
||||||
"chalk": "^3.0.0",
|
|
||||||
"concurrently": "^5.0.0",
|
|
||||||
"cross-env": "^6.0.3",
|
|
||||||
"cross-spawn": "^7.0.1",
|
|
||||||
"css-loader": "^3.2.0",
|
|
||||||
"detect-port": "^1.3.0",
|
|
||||||
"electron": "7.2.4",
|
|
||||||
"electron-builder": "^22.1.0",
|
|
||||||
"electron-devtools-installer": "^2.2.4",
|
|
||||||
"electron-rebuild": "^1.8.2",
|
|
||||||
"enzyme": "^3.7.0",
|
|
||||||
"enzyme-adapter-react-16": "^1.7.0",
|
|
||||||
"enzyme-to-json": "^3.3.4",
|
|
||||||
"eslint": "^6.6.0",
|
|
||||||
"eslint-config-airbnb": "^18.0.1",
|
|
||||||
"eslint-config-erb": "^0.1.1",
|
|
||||||
"eslint-config-prettier": "^6.6.0",
|
|
||||||
"eslint-formatter-pretty": "^3.0.0",
|
|
||||||
"eslint-import-resolver-webpack": "^0.11.0",
|
|
||||||
"eslint-plugin-compat": "^3.3.0",
|
|
||||||
"eslint-plugin-flowtype": "^4.4.1",
|
|
||||||
"eslint-plugin-import": "^2.18.2",
|
|
||||||
"eslint-plugin-jest": "^23.0.4",
|
|
||||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
|
||||||
"eslint-plugin-react": "^7.16.0",
|
|
||||||
"eslint-plugin-testcafe": "^0.2.1",
|
|
||||||
"fbjs-scripts": "^1.2.0",
|
|
||||||
"file-loader": "^4.2.0",
|
|
||||||
"flow-bin": "^0.112.0",
|
|
||||||
"flow-runtime": "^0.17.0",
|
|
||||||
"flow-typed": "^2.6.2",
|
|
||||||
"identity-obj-proxy": "^3.0.0",
|
|
||||||
"jest": "^24.9.0",
|
|
||||||
"lint-staged": "^9.4.3",
|
|
||||||
"mini-css-extract-plugin": "^0.8.0",
|
|
||||||
"node-sass": "^4.13.0",
|
|
||||||
"opencollective-postinstall": "^2.0.2",
|
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"react-test-renderer": "^16.12.0",
|
|
||||||
"redux-logger": "^3.0.6",
|
|
||||||
"rimraf": "^3.0.0",
|
|
||||||
"sass-loader": "^8.0.0",
|
|
||||||
"sinon": "^7.5.0",
|
|
||||||
"spectron": "^9.0.0",
|
|
||||||
"style-loader": "^1.0.0",
|
|
||||||
"stylelint": "^12.0.0",
|
|
||||||
"stylelint-config-prettier": "^6.0.0",
|
|
||||||
"stylelint-config-standard": "^19.0.0",
|
|
||||||
"terser-webpack-plugin": "^2.2.1",
|
|
||||||
"testcafe": "^1.6.1",
|
|
||||||
"testcafe-browser-provider-electron": "^0.0.12",
|
|
||||||
"testcafe-live": "^0.1.4",
|
|
||||||
"testcafe-react-selectors": "^3.3.0",
|
|
||||||
"url-loader": "^2.2.0",
|
|
||||||
"webpack": "^4.41.2",
|
|
||||||
"webpack-bundle-analyzer": "^3.6.0",
|
|
||||||
"webpack-cli": "^3.3.10",
|
|
||||||
"webpack-dev-server": "^3.9.0",
|
|
||||||
"webpack-merge": "^4.2.2",
|
|
||||||
"yarn": "^1.19.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"scripts": {
|
||||||
"@fortawesome/fontawesome-free": "^5.11.2",
|
"postinstall": "electron-builder install-app-deps",
|
||||||
"@hot-loader/react-dom": "^16.11.0",
|
"develop": "gulp develop",
|
||||||
"connected-react-router": "^6.6.0",
|
"test": "electron-mocha --renderer -R spec --require @babel/register test/**/*.spec.js",
|
||||||
"core-js": "3.4.1",
|
"lint": "eslint --no-ignore tasks app test *.js",
|
||||||
"devtron": "^1.4.0",
|
"format": "npm run private:format -- --write",
|
||||||
"electron-debug": "^3.0.1",
|
"check-format": "npm run private:format -- --list-different",
|
||||||
"electron-log": "^3.0.9",
|
"pack:mac": "gulp pack-mac",
|
||||||
"electron-updater": "^4.2.0",
|
"pack:win": "gulp pack-win",
|
||||||
"formik": "^2.1.4",
|
"pack:linux": "gulp pack-linux",
|
||||||
"history": "^4.10.1",
|
"private:format": "prettier gulpfile.js babel.config.js \"tasks/*.js\" \"app/**/*.js\" \"test/**/*.js\""
|
||||||
"react": "^16.12.0",
|
}
|
||||||
"react-dom": "^16.12.0",
|
|
||||||
"react-hot-loader": "^4.12.18",
|
|
||||||
"react-redux": "^7.1.3",
|
|
||||||
"react-router": "^5.1.2",
|
|
||||||
"react-router-dom": "^5.1.2",
|
|
||||||
"redux": "^4.0.4",
|
|
||||||
"redux-thunk": "^2.3.0",
|
|
||||||
"source-map-support": "^0.5.16",
|
|
||||||
"yup": "^0.29.1"
|
|
||||||
},
|
|
||||||
"devEngines": {
|
|
||||||
"node": ">=7.x",
|
|
||||||
"npm": ">=4.x",
|
|
||||||
"yarn": ">=0.21.3"
|
|
||||||
},
|
|
||||||
"browserslist": "electron 1.6"
|
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 361 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 12 KiB |
9
Dashboard/tasks/assets.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
const { src, dest } = require('gulp');
|
||||||
|
|
||||||
|
function copyHtml() {
|
||||||
|
return src('app/renderer/index.html').pipe(dest('build/renderer'));
|
||||||
|
}
|
||||||
|
|
||||||
|
copyHtml.displayName = 'copy-html';
|
||||||
|
|
||||||
|
exports.copyHtml = copyHtml;
|
27
Dashboard/tasks/distribution.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const builder = require('electron-builder');
|
||||||
|
|
||||||
|
function packWin() {
|
||||||
|
return builder.build({
|
||||||
|
targets: builder.Platform.WINDOWS.createTarget(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function packMac() {
|
||||||
|
return builder.build({
|
||||||
|
targets: builder.Platform.MAC.createTarget(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function packLinux() {
|
||||||
|
return builder.build({
|
||||||
|
targets: builder.Platform.LINUX.createTarget(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
packWin.displayName = 'builder-win';
|
||||||
|
packMac.displayName = 'builder-mac';
|
||||||
|
packLinux.displayName = 'builder-linux';
|
||||||
|
|
||||||
|
exports.packWin = packWin;
|
||||||
|
exports.packMac = packMac;
|
||||||
|
exports.packLinux = packLinux;
|
23
Dashboard/tasks/electron.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const electron = require('electron');
|
||||||
|
|
||||||
|
let subprocess;
|
||||||
|
|
||||||
|
function startElectron(done) {
|
||||||
|
subprocess = spawn(electron, ['.', '--no-sandbox'], {
|
||||||
|
env: { ...process.env, NODE_ENV: 'development' },
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopElectron() {
|
||||||
|
subprocess.kill();
|
||||||
|
return subprocess;
|
||||||
|
}
|
||||||
|
|
||||||
|
startElectron.displayName = 'start-electron';
|
||||||
|
stopElectron.displayName = 'stop-electron';
|
||||||
|
|
||||||
|
exports.start = startElectron;
|
||||||
|
exports.stop = stopElectron;
|
43
Dashboard/tasks/hotreload.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const { series, src, dest } = require('gulp');
|
||||||
|
const inject = require('gulp-inject-string');
|
||||||
|
|
||||||
|
const browserSync = require('browser-sync').create();
|
||||||
|
|
||||||
|
function startBrowserSync(done) {
|
||||||
|
browserSync.init(
|
||||||
|
{
|
||||||
|
ui: false,
|
||||||
|
localOnly: true,
|
||||||
|
port: 35829,
|
||||||
|
ghostMode: false,
|
||||||
|
open: false,
|
||||||
|
notify: false,
|
||||||
|
logSnippet: false,
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
done(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function injectBrowserSync() {
|
||||||
|
return src('app/renderer/index.html')
|
||||||
|
.pipe(inject.before('</body>', browserSync.getOption('snippet')))
|
||||||
|
.pipe(
|
||||||
|
inject.after('script-src', " 'unsafe-eval' " + browserSync.getOption('urls').get('local')),
|
||||||
|
)
|
||||||
|
.pipe(dest('build/renderer'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadBrowser(done) {
|
||||||
|
browserSync.reload();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
startBrowserSync.displayName = 'start-hotreload';
|
||||||
|
injectBrowserSync.displayName = 'inject-hotreload';
|
||||||
|
reloadBrowser.displayName = 'reload-hotreload';
|
||||||
|
|
||||||
|
exports.start = series(startBrowserSync, injectBrowserSync);
|
||||||
|
exports.inject = injectBrowserSync;
|
||||||
|
exports.reload = reloadBrowser;
|
25
Dashboard/tasks/scripts.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const { src, dest } = require('gulp');
|
||||||
|
const babel = require('gulp-babel');
|
||||||
|
const sourcemaps = require('gulp-sourcemaps');
|
||||||
|
const inject = require('gulp-inject-string');
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
return src('app/**/*.js')
|
||||||
|
.pipe(babel())
|
||||||
|
.pipe(inject.replace('process.env.NODE_ENV', '"production"'))
|
||||||
|
.pipe(dest('build'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function developBuild() {
|
||||||
|
return src('app/**/*.js')
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
|
.pipe(babel())
|
||||||
|
.pipe(sourcemaps.write())
|
||||||
|
.pipe(dest('build'));
|
||||||
|
}
|
||||||
|
|
||||||
|
build.displayName = 'build-scripts';
|
||||||
|
developBuild.displayName = 'dev-build-scripts';
|
||||||
|
|
||||||
|
exports.build = build;
|
||||||
|
exports.developBuild = developBuild;
|
32
Dashboard/tasks/watch.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
const { parallel, series, watch } = require('gulp');
|
||||||
|
const electron = require('./electron');
|
||||||
|
const hotreload = require('./hotreload');
|
||||||
|
const assets = require('./assets');
|
||||||
|
const scripts = require('./scripts');
|
||||||
|
|
||||||
|
function watchMainScripts() {
|
||||||
|
return watch(['app/main/**/*.js'], series(scripts.developBuild, electron.stop, electron.start));
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchRendererScripts() {
|
||||||
|
return watch(['app/renderer/**/*.js'], series(scripts.developBuild, hotreload.reload));
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchHtml() {
|
||||||
|
return watch(
|
||||||
|
['app/renderer/index.html'],
|
||||||
|
series(assets.copyHtml, hotreload.inject, hotreload.reload),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchMainScripts.displayName = 'watch-main-scripts';
|
||||||
|
watchRendererScripts.displayName = 'watch-renderer-scripts';
|
||||||
|
watchHtml.displayName = 'watch-html';
|
||||||
|
|
||||||
|
exports.start = series(
|
||||||
|
assets.copyHtml,
|
||||||
|
scripts.developBuild,
|
||||||
|
hotreload.start,
|
||||||
|
electron.start,
|
||||||
|
parallel(watchMainScripts, watchRendererScripts, watchHtml),
|
||||||
|
);
|
5
Dashboard/test/.eslintrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"mocha": true
|
||||||
|
}
|
||||||
|
}
|
54
Dashboard/test/actions/user.spec.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import configureMockStore from 'redux-mock-store';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
import actions from '../../app/renderer/actions/user';
|
||||||
|
|
||||||
|
const mockStore = configureMockStore([thunk]);
|
||||||
|
|
||||||
|
describe('actions', () => {
|
||||||
|
describe('user', () => {
|
||||||
|
it('should log in', () => {
|
||||||
|
const store = mockStore({});
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'USER_LOGIN',
|
||||||
|
payload: {
|
||||||
|
username: 'John Doe',
|
||||||
|
loggedIn: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
actions.login({
|
||||||
|
username: 'John Doe',
|
||||||
|
loggedIn: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(store.getActions()).deep.equal(expectedActions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should logout', () => {
|
||||||
|
const store = mockStore({});
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: 'USER_LOGOUT',
|
||||||
|
payload: {
|
||||||
|
username: '',
|
||||||
|
loggedIn: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
actions.logout({
|
||||||
|
username: '',
|
||||||
|
loggedIn: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(store.getActions()).deep.equal(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
30
Dashboard/test/reducers/user.spec.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import reducer from '../../app/renderer/reducers/user';
|
||||||
|
|
||||||
|
describe('reducers', () => {
|
||||||
|
describe('user', () => {
|
||||||
|
it('should handle USER_LOGIN', () => {
|
||||||
|
const action = {
|
||||||
|
type: 'USER_LOGIN',
|
||||||
|
payload: {
|
||||||
|
username: 'John Doe',
|
||||||
|
loggedIn: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const test = Object.assign({}, action.payload);
|
||||||
|
expect(reducer({}, action)).to.deep.equal(test);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle USER_LOGOUT', () => {
|
||||||
|
const action = {
|
||||||
|
type: 'USER_LOGOUT',
|
||||||
|
payload: {
|
||||||
|
username: '',
|
||||||
|
loggedIn: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const test = Object.assign({}, action.payload);
|
||||||
|
expect(reducer({}, action)).to.deep.equal(test);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|