Skip to content
This repository has been archived by the owner on Dec 16, 2021. It is now read-only.

[WIP] React FE #53

Merged
merged 5 commits into from
Aug 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .compilerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"env": {
"development": {
"application/javascript": {
"presets": ["node7"],
"presets": ["node7", "react"],
"plugins": ["transform-class-properties"],
"sourceMaps": "inline"
},
"text/less": {
Expand All @@ -11,7 +12,8 @@
},
"production": {
"application/javascript": {
"presets": ["node7"],
"presets": ["node7", "react"],
"plugins": ["transform-class-properties"],
"sourceMaps": "none"
}
}
Expand Down
14 changes: 13 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,41 @@
"node7"
]
},
"standard": {
"parser": "babel-eslint"
},
"dependencies": {
"electron-compile": "^6.4.1",
"electron-log": "^2.2.7",
"electron-sudo": "^4.0.12",
"electron-window-state": "^4.1.1",
"flexboxgrid": "^6.3.1",
"font-awesome": "^4.7.0",
"once": "^1.4.0",
"osenv": "^0.1.4",
"prismjs": "^1.6.0",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-fontawesome": "^1.6.1",
"react-prism": "^4.3.0",
"request": "^2.81.0",
"semver": "^5.3.0",
"yo-yo": "^1.4.1"
},
"devDependencies": {
"ava": "^0.21.0",
"babel-eslint": "^7.2.3",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-node7": "^1.5.0",
"babel-preset-react": "^6.24.1",
"babel-register": "^6.24.1",
"devtron": "^1.4.0",
"electron-devtools-installer": "^2.2.0",
"electron-forge": "^3.0.5",
"electron-prebuilt-compile": "1.7.4",
"electron-process-manager": "0.0.4",
"mockery": "^2.1.0",
"react-hot-loader": "^3.0.0-beta.6",
"sinon": "^2.3.8",
"spectron": "^3.7.2",
"standard": "^10.0.2"
Expand Down
5 changes: 5 additions & 0 deletions spec/__mocks__/electron-compile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sinon from 'sinon'

export const electronCompileMock = {
enableLiveReload: sinon.spy()
}
10 changes: 10 additions & 0 deletions spec/__mocks__/electron-devtools-installer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import sinon from 'sinon'

const installStub = sinon.stub()
installStub.returns(Promise.resolve())

export const electronDevtoolsInstallerMock = {
__esModule: true,
default: installStub,
REACT_DEVELOPER_TOOLS: 'react'
}
14 changes: 12 additions & 2 deletions spec/__mocks__/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,19 @@ class BrowserWindow extends EventEmitter {
}
}

class CommandLine {
constructor () {
this.appendSwitch = sinon.stub()
}
}

class App extends EventEmitter {
constructor () {
super()

this.getName = sinon.stub()
this.getPah = sinon.stub()
this.getPath = sinon.stub()
this.commandLine = new CommandLine()
}
}

Expand Down Expand Up @@ -90,7 +97,8 @@ export const electronMock = {
getCurrentWindow: sinon.stub(),
require: sinon.stub(),
Menu: MockMenu,
MenuItem: MockMenuItem
MenuItem: MockMenuItem,
app: new App()
},
ipcRenderer: {
send: sinon.stub()
Expand All @@ -104,3 +112,5 @@ export const electronMock = {
screen: new Screen(),
BrowserWindow
}

export const electronMainMock = Object.assign({}, electronMock, { remote: null })
39 changes: 35 additions & 4 deletions spec/main/developer-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import test from 'ava'
import mockery from 'mockery'
import sinon from 'sinon'

import { electronMock } from '../../spec/__mocks__/electron'
import { electronMainMock } from '../../spec/__mocks__/electron'

require('../setup').setup(test)

test('it installs devtron if not installed', (t) => {
mockery.registerMock('electron', electronMock)
mockery.registerMock('electron', electronMainMock)
mockery.registerMock('devtron', { install: sinon.spy() })

const { BrowserWindow } = require('electron')
Expand All @@ -23,7 +23,7 @@ test('it installs devtron if not installed', (t) => {
})

test('does not it installs devtron if already installed', (t) => {
mockery.registerMock('electron', electronMock)
mockery.registerMock('electron', electronMainMock)
mockery.registerMock('devtron', { install: sinon.spy() })

const { BrowserWindow } = require('electron')
Expand All @@ -32,8 +32,39 @@ test('does not it installs devtron if already installed', (t) => {
const { DeveloperFeatures } = require('../../src/main/developer')

//eslint-disable-next-line
const developerFeatures = new DeveloperFeatures()
new DeveloperFeatures()

const devtron = require('devtron')
t.is(devtron.install.callCount, 0)
})

test('it enables react HMR', (t) => {
mockery.registerMock('electron', electronMainMock)
mockery.registerMock('devtron', { install: sinon.spy() })
mockery.registerMock('electron-compile', { enableLiveReload: sinon.spy() })

const { DeveloperFeatures } = require('../../src/main/developer')
//eslint-disable-next-line
new DeveloperFeatures()

const electronCompile = require('electron-compile')

t.is(electronCompile.enableLiveReload.callCount, 1)
t.is(electronCompile.enableLiveReload.firstCall.args[0].strategy, 'react-hmr')
})

test('it attempts to install react dev tools', (t) => {
mockery.registerMock('electron', electronMainMock)
mockery.registerMock('devtron', { install: sinon.spy() })
mockery.registerMock('electron-devtools-installer', { __esModule: true, default: sinon.stub(), REACT_DEVELOPER_TOOLS: 'react-tools' })

const electronDevtoolsInstaller = require('electron-devtools-installer')
electronDevtoolsInstaller.default.returns(Promise.resolve())

const { DeveloperFeatures } = require('../../src/main/developer')
//eslint-disable-next-line
new DeveloperFeatures()

t.is(electronDevtoolsInstaller.default.callCount, 1)
t.is(electronDevtoolsInstaller.default.firstCall.args[0], 'react-tools')
})
8 changes: 7 additions & 1 deletion spec/setup.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import mockery from 'mockery'

import { logMock } from './__mocks__/electron-log'
import { electronDevtoolsInstallerMock } from './__mocks__/electron-devtools-installer'
import { electronCompileMock } from './__mocks__/electron-compile'
import { electronMock } from './__mocks__/electron'
import { windowStateMock } from './__mocks__/electron-window-state'

export function setup (test) {
test.before((t) => {
mockery.enable()
mockery.enable({
useCleanCache: true
})
mockery.warnOnUnregistered(false)
})

Expand All @@ -16,6 +20,8 @@ export function setup (test) {
mockery.registerMock('electron-window-state', windowStateMock)
mockery.registerMock('electron', electronMock)
mockery.registerMock('electron-log', logMock)
mockery.registerMock('electron-devtools-installer', electronDevtoolsInstallerMock)
mockery.registerMock('electron-compile', electronCompileMock)
})

test.after((t) => {
Expand Down
15 changes: 15 additions & 0 deletions src/main/developer.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { BrowserWindow } from 'electron'
import devtron from 'devtron'
import * as electronCompile from 'electron-compile'
import installDevTools, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer'

import { logger } from '../logger'

export class DeveloperFeatures {
constructor () {
this.extensions = BrowserWindow.getDevToolsExtensions()
this.enableHMR()
this.installDevtron()
this.installReactTools()
}

enableHMR () {
electronCompile.enableLiveReload({
strategy: 'react-hmr'
})
}

installDevtron () {
Expand All @@ -17,4 +27,9 @@ export class DeveloperFeatures {
devtron.install()
}
}

installReactTools () {
installDevTools(REACT_DEVELOPER_TOOLS)
.catch((err) => logger.error('Failed to install React dev tools', err))
}
}
6 changes: 6 additions & 0 deletions src/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export class App {
this.onReady()
}
})

// Fancy scrollbars
app.commandLine.appendSwitch('enable-smooth-scrolling', '1')
app.commandLine.appendSwitch('enable-overlay-scrollbar', '1')
// Fix HDPI zoom bug
app.commandLine.appendSwitch('enable-use-zoom-for-dsf', 'false')
}

onReady () {
Expand Down
3 changes: 2 additions & 1 deletion src/main/window-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class WindowManager {
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height
height: mainWindowState.height,
minHeight: 450
})

mainWindowState.manage(browserWindow)
Expand Down
98 changes: 98 additions & 0 deletions src/renderer/components/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from 'react'

import { InstallingOverlay } from './InstallingOverlay'
import { LeftPanel } from './LeftPanel'
import { RightPanel } from './RightPanel'

import { Installer } from '../lib/Installer'
import getInstalledVersion from '../lib/check-node'
import getVersions from '../lib/versions'

const INSTALL_STATUS = {
NOT_INSTALLING: 0,
INSTALLING: 1,
SUCCESS: 2,
ERROR: 3
}

export class App extends React.Component {
state = {
installStatus: INSTALL_STATUS.NOT_INSTALLING,
installError: null,
versions: null,
currentVersion: null
}

componentDidMount () {
this.loadVersionList()
getInstalledVersion((err, version) => {
if (!err) {
this.setState({
currentVersion: version
})
}
})
}

cancelInstall = () => {
if (this._currentInstalller) {
this._currentInstalller.cancel()
}
this.setState({
installStatus: INSTALL_STATUS.NOT_INSTALLING,
installError: null
})
}

installVersion = (version) => {
this.setState({
installStatus: INSTALL_STATUS.INSTALLING
})
const installer = new Installer(version)
this._currentInstalller = installer
installer.on('error', (err) => {
console.error(err)
this.setState({
installStatus: INSTALL_STATUS.ERROR,
installError: err
})
})
installer.on('done', () => {
this.setState({
currentVersion: version,
installStatus: INSTALL_STATUS.SUCCESS
})
delete this._currentInstalller
})
installer.install()
}

loadVersionList () {
window.fetch('https://nodejs.org/dist/index.json')
.then(r => r.json())
.then(getVersions)
.then((versions) => {
this.setState({
versions
})
})
}

render () {
return (
<div id='main'>
<InstallingOverlay
installing={this.state.installStatus === INSTALL_STATUS.INSTALLING}
error={this.state.installError}
onCancel={this.cancelInstall}
/>
<LeftPanel
versions={this.state.versions}
currentVersion={this.state.currentVersion}
installVersion={this.installVersion}
/>
<RightPanel />
</div>
)
}
}
Loading