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

Commit

Permalink
feat: focus window upon notification click
Browse files Browse the repository at this point in the history
Upon clicking on a new email notification the application window will be showed

fix #411
  • Loading branch information
kontrollanten committed Sep 2, 2020
1 parent eae1175 commit bc95060
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 83 deletions.
185 changes: 109 additions & 76 deletions config/webpack.renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,92 +5,125 @@ const { spawn } = require('child_process');

const env = process.env.NAME || 'development';

module.exports = {
devtool: 'source-map',
target: 'electron-renderer',
mode: env,
const outputPath = path.join(__dirname, '../app');

entry: [
path.join(__dirname, '../src/renderer/index.js'),
],
module.exports = [
{
devtool: 'source-map',
target: 'electron-renderer',
mode: env,
entry: [
path.join(__dirname, '../src/renderer/index.js'),
],

output: {
path: path.join(__dirname, '../app'),
filename: 'renderer.js',
},
output: {
path: outputPath,
filename: 'renderer.js',
},

module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
{
loader: 'css-loader',
options: {
modules: true,
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: true,
},
},
{
loader: 'sass-loader',
},
],
},
{
test: /\.svg$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
},
{
loader: 'sass-loader',
},
],
},
{
test: /\.svg$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
},
},
{
test: /\.png$/,
use: {
loader: 'url-loader',
{
test: /\.png$/,
use: {
loader: 'url-loader',
},
},
},
],
},
],
},

plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, '../src/renderer/index.html'),
}),
],
plugins: [
new webpack.DefinePlugin({
OUTPUT_DIR: JSON.stringify(outputPath),
}),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, '../src/renderer/index.html'),
}),
],

devServer: {
headers: { 'Access-Control-Allow-Origin': '*' },
lazy: false,
compress: true,
noInfo: true,
stats: 'errors-only',
inline: true,
hot: true,
historyApiFallback: {
index: './app/index.html'
},
devServer: {
headers: { 'Access-Control-Allow-Origin': '*' },
lazy: false,
compress: true,
noInfo: true,
stats: 'errors-only',
inline: true,
hot: true,
historyApiFallback: {
index: './app/index.html'
},

before() {
// eslint-disable-next-line no-console
console.log('Starting Main Process...');
spawn('npm', ['run', 'start-main-dev'], {
shell: true,
env: process.env,
stdio: 'inherit'
})
.on('close', code => process.exit(code))
before() {
// eslint-disable-next-line no-console
.on('error', spawnError => console.error(spawnError));
}
console.log('Starting Main Process...');
spawn('npm', ['run', 'start-main-dev'], {
shell: true,
env: process.env,
stdio: 'inherit'
})
.on('close', code => process.exit(code))
// eslint-disable-next-line no-console
.on('error', spawnError => console.error(spawnError));

console.log('Starting Webview Preload Process...');
spawn('yarn', ['start', '--config-name webview-preload'], {
shell: true,
env: process.env,
stdio: 'inherit'
})
.on('close', code => process.exit(code))
// eslint-disable-next-line no-console
.on('error', spawnError => console.error(spawnError));
}
},
},
{
entry: path.join(__dirname, '../src/renderer/lib/webview-preload.js'),
target: 'electron-renderer',
name: 'webview-preload',
devtool: 'cheap-module-source-map',
mode: env,
output: {
path: outputPath,
publicPath: '/',
filename: 'webview-preload.js',
},
devServer: {
hot: false,
inline: false,
writeToDisk: true,
},
},
};
];
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
"lcov",
"text"
],
"globals": {
"OUTPUT_DIR": "/some/path"
},
"setupFilesAfterEnv": [
"<rootDir>/src/renderer/tests/setup.js"
],
Expand Down
6 changes: 5 additions & 1 deletion src/main/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path';
import { app, Menu } from 'electron';
import { app, ipcMain, Menu } from 'electron';
import { autoUpdater } from 'electron-updater';
import electronDebug from 'electron-debug';
import createWindow from './helpers/window';
Expand Down Expand Up @@ -33,6 +33,10 @@ require('electron-context-menu')();
let mainWindow;
let isQuitting = false;

ipcMain.on('notificationClick', () => {
mainWindow.show();
});

function createMainWindow() {
if (process.argv.indexOf('test') !== -1) {
try {
Expand Down
24 changes: 21 additions & 3 deletions src/main/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { app, BrowserWindow } = require('electron');
const { app, ipcMain, BrowserWindow } = require('electron');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
Expand All @@ -10,9 +10,11 @@ chai.use(sinonChai);
describe('App', () => {
const sandbox = sinon.createSandbox();
const originalPlatform = process.platform;
const getOnReadyCb = () => app.on.getCalls().find(call => call.args[0] === 'ready').args[1];

beforeEach(() => {
sandbox.stub(app, 'requestSingleInstanceLock').returns(true);
sandbox.stub(ipcMain, 'on');
});

afterEach(() => {
Expand All @@ -24,13 +26,29 @@ describe('App', () => {
});
});

it('should listen for ipcMain notificationClick', async () => {
sandbox.spy(BrowserWindow.prototype, 'show');
sandbox.stub(app, 'on');
require('./');
const onReadyCb = getOnReadyCb();

await onReadyCb();

expect(ipcMain.on).to.have.been.calledWith('notificationClick', sinon.match.func);
ipcMain.on.getCalls()
.find(call => call.args[0] === 'notificationClick')
.args[1]();

expect(BrowserWindow.prototype.show).to.have.been.called;
});

it('should not throw an exception upon ready', async () => {
sandbox.spy(app, 'on');
require('./');

expect(app.on).to.have.been.called;

const onReadyCb = app.on.getCalls().find(call => call.args[0] === 'ready').args[1];
const onReadyCb = getOnReadyCb();
expect(async () => await onReadyCb()).to.not.throw();
});

Expand All @@ -39,7 +57,7 @@ describe('App', () => {
sandbox.spy(app, 'on');
require('./');

const onReadyCb = app.on.getCalls().find(call => call.args[0] === 'ready').args[1];
const onReadyCb = getOnReadyCb();
Object.defineProperty(process, 'platform', {
value: 'win32',
});
Expand Down
1 change: 1 addition & 0 deletions src/renderer/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
},
globals: {
module: true,
OUTPUT_DIR: true,
},
overrides: [
{
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/lib/webview-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export class WebviewHandler {
}

const webview = document.createElement('webview');

const preloadPath = `file://${OUTPUT_DIR}/webview-preload.js`;

webview.setAttribute('preload', preloadPath);
webview.setAttribute('src', url);
webview.setAttribute('style', webviewStyle);
webview.setAttribute('data-name', name);
Expand Down
1 change: 1 addition & 0 deletions src/renderer/lib/webview-handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ describe('lib/WebviewHandler', () => {
expect(mockElem.setAttribute).to.have.been.calledWith('src', url);
expect(mockElem.setAttribute).to.have.been.calledWith('style', sinon.match(/absolute/));
expect(mockElem.setAttribute).to.have.been.calledWith('data-name', name);
expect(mockElem.setAttribute).to.have.been.calledWith('preload', sinon.match(/^file:\/\//));

expect(webviewHandler.container.appendChild).to.have.been.calledWith(mockElem);
expect(webviewHandler.addedWebviews).to.eql([name]);
Expand Down
13 changes: 13 additions & 0 deletions src/renderer/lib/webview-preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ipcRenderer } from 'electron';

const originalNotification = window.Notification;

window.Notification = function(title, opts) {
const _notice = new originalNotification(title, opts);

_notice.addEventListener('click', () => {
ipcRenderer.sendToHost('notificationClick', opts);
});

return _notice;
};
31 changes: 31 additions & 0 deletions src/renderer/lib/webview-preload.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { expect } from 'chai';
import sinon from 'sinon';
import { ipcRenderer } from 'electron';

describe('/renderer/li/webview-preload', () => {
const sandbox = sinon.createSandbox();
let originalNotification;

beforeEach(() => {
originalNotification = sinon.stub();
window.Notification = originalNotification;
require('./webview-preload');
});

afterEach(() => {
sandbox.restore();
});

it('should ipcRenderer.sendToHost upon click event', () => {
const mockNoti = document.createElement('div');
originalNotification.returns(mockNoti);
ipcRenderer.sendToHost = sinon.spy();

const noti = new Notification('read this');

const event = new MouseEvent('click', { bubbles: true, cancelable: false });
noti.dispatchEvent(event);

expect(ipcRenderer.sendToHost).to.have.been.calledWith('notificationClick');
});
});
9 changes: 9 additions & 0 deletions src/renderer/middlewares/Webviews/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ipcRenderer } from 'electron';
import WebviewHandler from '../../lib/webview-handler';
import {
DISPLAY_WEBVIEW,
Expand All @@ -17,6 +18,14 @@ const WebviewsMiddleware = ({ dispatch }) => next => action => {
const webview = WebviewHandler.addWebview(action.name, url);
dispatch(monitorWebview(webview, action.name));
createdWebviews[action.name] = true;

webview.addEventListener('ipc-message', (event) => {
if (event.channel === 'notificationClick') {
ipcRenderer.send('notificationClick', event);

window.location.assign(`#/mailbox/${action.name}`);
}
});
}

WebviewHandler.show();
Expand Down
Loading

0 comments on commit bc95060

Please sign in to comment.