From 3a7a794afb7f118232168fe9ef2b16816d69839a Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Mon, 15 Feb 2016 23:58:46 +0900 Subject: [PATCH 01/26] Verify codes are formatted --- gulpfile.js | 65 +++++++++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 4042483e..550bd257 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,6 +7,8 @@ var webpack = require('webpack-stream'); var named = require('vinyl-named'); var changed = require('gulp-changed'); var esformatter = require('gulp-esformatter'); +var esformatter_origin = require('esformatter'); +var through = require('through2'); var del = require('del'); var electron = require('electron-connect').server.create({ path: './dist' @@ -16,35 +18,62 @@ var packager = require('electron-packager'); var sources = ['**/*.js', '**/*.css', '**/*.html', '!**/node_modules/**', '!dist/**', '!release/**']; gulp.task('prettify', ['prettify:sources', 'prettify:jsx']); +gulp.task('prettify:verify', ['prettify:sources:verify', 'prettify:jsx:verify']) + +var prettify_options = { + html: { + indentSize: 2 + }, + css: { + indentSize: 2 + }, + js: { + indentSize: 2, + braceStyle: "end-expand" + } +}; gulp.task('prettify:sources', ['sync-meta'], function() { + prettify_options.mode = "VERIFY_AND_WRITE"; return gulp.src(sources) - .pipe(prettify({ - html: { - indentSize: 2 - }, - css: { - indentSize: 2 - }, - js: { - indentSize: 2, - braceStyle: "end-expand" - } - })) + .pipe(prettify(prettify_options)) .pipe(gulp.dest('.')); }); +gulp.task('prettify:sources:verify', function() { + prettify_options.mode = "VERIFY_ONLY"; + prettify_options.showDiff = false; + return gulp.src(sources) + .pipe(prettify(prettify_options)); +}); + + +var esformatter_jsx_options = { + indent: { + value: ' ' + }, + plugins: ['esformatter-jsx'] +}; + gulp.task('prettify:jsx', function() { return gulp.src('src/browser/**/*.jsx') - .pipe(esformatter({ - indent: { - value: ' ' - }, - plugins: ['esformatter-jsx'] - })) + .pipe(esformatter(esformatter_jsx_options)) .pipe(gulp.dest('src/browser')); }); +gulp.task('prettify:jsx:verify', function() { + return gulp.src('src/browser/**/*.jsx') + .pipe(through.obj(function(file, enc, cb) { + var result = esformatter_origin.diff.unified(file.contents.toString(), esformatter_origin.rc(file.path, esformatter_jsx_options)); + if (result !== "") { + console.log('Error: ' + file.path + ' must be formatted'); + process.exit(1); + } + cb(); + })); +}); + + gulp.task('build', ['sync-meta', 'webpack', 'copy'], function() { return gulp.src('src/package.json') .pipe(gulp.dest('dist')); diff --git a/package.json b/package.json index 50b9969c..f0b6628d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "start": "electron dist", "watch": "gulp watch", "serve": "gulp watch", - "test": "gulp build && mocha", + "test": "gulp build && mocha && gulp prettify:verify", "package": "gulp package", "package:windows": "gulp package:windows", "package:osx": "gulp package:osx", From 605ed90cf37b65b5dd97ddcb2e0c4f4e5c9d10fb Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 16 Feb 2016 00:03:28 +0900 Subject: [PATCH 02/26] Add verify-test for CircleCI --- circle.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/circle.yml b/circle.yml index 08b563b8..221cc9aa 100644 --- a/circle.yml +++ b/circle.yml @@ -28,6 +28,7 @@ dependencies: test: override: - node_modules/.bin/mocha --reporter mocha-circleci-reporter + - node_modules/.bin/gulp prettify:verify post: - mv test-results.xml $CIRCLE_TEST_REPORTS/ From 5783cbbad9758aa10e53d8476b52e2d9f7cc4586 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 16 Feb 2016 00:32:21 +0900 Subject: [PATCH 03/26] Install npm 3.3.12 manually in CircleCI Now CircleCI doesn't contain npm 3.x https://discuss.circleci.com/t/wrong-npm-version-with-node-5-0-5-1/827 --- circle.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/circle.yml b/circle.yml index 221cc9aa..6c64fe81 100644 --- a/circle.yml +++ b/circle.yml @@ -13,6 +13,8 @@ dependencies: cache_directories: - "~/.electron" - "src/node_modules" + pre: + - npm install -g npm@3.3.12 post: - mkdir -p ~/.electron - docker run --rm -it -v `pwd`:/home/xclient/electron-mattermost -v ~/.electron:/home/xclient/.electron yuyaoc/em-builder:dev ./electron-mattermost/docker/package_in_docker.sh From dbd652eb759577ae72bf4fe3c5cd7015e7cd2a9f Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 20 Feb 2016 23:59:59 +0900 Subject: [PATCH 04/26] Install through2 explicitly --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index f0b6628d..e0d14742 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "mocha-circleci-reporter": "0.0.1", "should": "^8.0.1", "style-loader": "^0.13.0", + "through2": "^2.0.1", "vinyl-named": "^1.1.0", "webdriverio": "^3.3.0", "webpack-stream": "^3.1.0" From 50084fe74f85ce7623b2d9456e671db02686c27d Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sun, 21 Feb 2016 00:08:38 +0900 Subject: [PATCH 05/26] Add engines for package.json --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 0a7c40c4..722c748d 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "main": "main.js", "author": "Yuya Ochiai", "license": "MIT", + "engines": { + "node": ">=4.2.0" + }, "scripts": { "install": "cd src && npm install", "postinstall": "npm run build", From c13afa3745bb7a02f90fe768dd613dd94481ee24 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Thu, 25 Feb 2016 22:21:28 +0900 Subject: [PATCH 06/26] Show a dot on tray icon to notify unread messages Tray icon is too small to show a number. So a dot(small circle) is used. --- src/browser/index.jsx | 6 ++++-- src/main.js | 15 ++++++++++++++- src/resources/tray_mention.png | Bin 0 -> 735 bytes src/resources/tray_unread.png | Bin 0 -> 715 bytes 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/resources/tray_mention.png create mode 100644 src/resources/tray_unread.png diff --git a/src/browser/index.jsx b/src/browser/index.jsx index a1097c75..059da87a 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -321,7 +321,9 @@ var showUnreadBadgeWindows = function(unreadCount, mentionCount) { // https://github.com/atom/electron/issues/4011 electron.ipcRenderer.send('win32-overlay', { overlayDataURL: dataURL, - description: description + description: description, + unreadCount: unreadCount, + mentionCount: mentionCount }); }; @@ -332,7 +334,7 @@ var showUnreadBadgeWindows = function(unreadCount, mentionCount) { const dataURL = badge.createDataURL('•'); sendBadge(dataURL, 'You have unread channels'); } else { - remote.getCurrentWindow().setOverlayIcon(null, ''); + sendBadge(null, 'You have no unread messages'); } } diff --git a/src/main.js b/src/main.js index 8dd38c02..f2a1b0f1 100644 --- a/src/main.js +++ b/src/main.js @@ -104,9 +104,22 @@ app.on('ready', function() { }); // Set overlay icon from dataURL + // Set trayicon to show "dot" ipc.on('win32-overlay', function(event, arg) { - var overlay = electron.nativeImage.createFromDataURL(arg.overlayDataURL); + const overlay = arg.overlayDataURL ? electron.nativeImage.createFromDataURL(arg.overlayDataURL) : null; mainWindow.setOverlayIcon(overlay, arg.description); + + var tray_image = null; + if (arg.mentionCount > 0) { + tray_image = 'tray_mention.png'; + } + else if (arg.unreadCount > 0) { + tray_image = 'tray_unread.png'; + } + else { + tray_image = 'tray.png'; + } + trayIcon.setImage(path.resolve(__dirname, 'resources', tray_image)); }); } diff --git a/src/resources/tray_mention.png b/src/resources/tray_mention.png new file mode 100644 index 0000000000000000000000000000000000000000..3a3ee1a99deac1d2a9cfbd85c85e118eccd618d5 GIT binary patch literal 735 zcmV<50wDc~P)XJ?1Y z%gc1hnSy0magr>T%Q^s_ot=>+H#Rm1fWyPXoS2xPrfDR}a5&7%%S)XkEz62|01N^^ zsZ3fGaC2%?4JhRqpNP_+iw~THiF;A0+#O zto2QEan#R)-M!SECa$lq696|iH))z?V+ynLcff9v*8|UX+k_C?Qpy7%#JHj;MmC#m z4~0Td6a_OgGtj@CphNVa)jEU+z1Lc|up2cFU>^W(Z*PrsI^DjoumAvf)6tJlkH_v2 z06^r=_q>OV#W(;k4**`Tw>=Vxn3YP!$mjEB@8omVDer;nlu%{uv~?fGN$$D6E6)o> zE$yDk7y3 zq&Qm*w7Xi#PDvo7i-76EEZn#ZWRYzbZc4#^7_qoAj3y?Hg=sMv$Y9c$$s8A%7p9F~ zc)Xdp_uO~RnRf-eAUPt0aJ=V5*LCkHiZbJ+e**X*gxI}WI{09vtF;0Bpt`Gd`-dw36i#H znpPwd;m*#^pei1Zb9;N6B$?0Wd47IwNjdWLMM*oEOfs9z_Frt9TU%QMz|GA~lH~sW zKGW$meR3Aj>-CZ(*=#l~0IXK4B*{XdKmZH|gIrixV7uKWNv^K0^6c!)BFSE_mrwxA z0D!LR0ssPm002PKG|3Q$hll8PyO8<>l>z+(WIoSYnu#bQpY z)w0XwvJ<&AO Date: Fri, 26 Feb 2016 00:06:41 +0900 Subject: [PATCH 07/26] Force to use LF and add editorconfig --- .editorconfig | 8 ++++++ gulpfile.js | 3 +++ src/browser/js/badge.js | 56 ++++++++++++++++++++--------------------- 3 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a86e0128 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true diff --git a/gulpfile.js b/gulpfile.js index 550bd257..a81f3f4e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -22,12 +22,15 @@ gulp.task('prettify:verify', ['prettify:sources:verify', 'prettify:jsx:verify']) var prettify_options = { html: { + eol: '\n', indentSize: 2 }, css: { + eol: '\n', indentSize: 2 }, js: { + eol: '\n', indentSize: 2, braceStyle: "end-expand" } diff --git a/src/browser/js/badge.js b/src/browser/js/badge.js index b77e1f22..0b0b168e 100644 --- a/src/browser/js/badge.js +++ b/src/browser/js/badge.js @@ -1,29 +1,29 @@ -'use strict'; - -var createDataURL = function(text) { - const scale = 2; // should rely display dpi - const size = 16 * scale; - const canvas = document.createElement('canvas'); - canvas.setAttribute('width', size); - canvas.setAttribute('height', size); - const ctx = canvas.getContext('2d'); - - // circle - ctx.fillStyle = "#FF1744"; // Material Red A400 - ctx.beginPath(); - ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2); - ctx.fill(); - - // text - ctx.fillStyle = "#ffffff" - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.font = (11 * scale) + "px sans-serif"; - ctx.fillText(text, size / 2, size / 2, size); - - return canvas.toDataURL(); -}; - -module.exports = { - createDataURL: createDataURL +'use strict'; + +var createDataURL = function(text) { + const scale = 2; // should rely display dpi + const size = 16 * scale; + const canvas = document.createElement('canvas'); + canvas.setAttribute('width', size); + canvas.setAttribute('height', size); + const ctx = canvas.getContext('2d'); + + // circle + ctx.fillStyle = "#FF1744"; // Material Red A400 + ctx.beginPath(); + ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2); + ctx.fill(); + + // text + ctx.fillStyle = "#ffffff" + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = (11 * scale) + "px sans-serif"; + ctx.fillText(text, size / 2, size / 2, size); + + return canvas.toDataURL(); +}; + +module.exports = { + createDataURL: createDataURL }; From 695c091baccd230bc25a6e9ff619308150ef566a Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 20 Feb 2016 21:36:09 +0900 Subject: [PATCH 08/26] Refactor desktop notification override --- src/browser/js/notification.js | 80 +++++++++++++++++++++++++++++++ src/browser/webview/mattermost.js | 56 +++++++--------------- 2 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 src/browser/js/notification.js diff --git a/src/browser/js/notification.js b/src/browser/js/notification.js new file mode 100644 index 00000000..eef0c4be --- /dev/null +++ b/src/browser/js/notification.js @@ -0,0 +1,80 @@ +const OriginalNotification = Notification; + +function override(eventHandlers) { + Notification = function(title, options) { + this.notification = new OriginalNotification(title, options); + if (eventHandlers.notification) { + eventHandlers.notification(); + } + }; + + // static properties + Notification.__defineGetter__('permission', function() { + return OriginalNotification.permission; + }); + + // instance properties + var defineReadProperty = function(property) { + Notification.prototype.__defineGetter__(property, function() { + return this.notification[property]; + }); + }; + defineReadProperty('title'); + defineReadProperty('dir'); + defineReadProperty('lang'); + defineReadProperty('body'); + defineReadProperty('tag'); + defineReadProperty('icon'); + defineReadProperty('data'); + defineReadProperty('silent'); + + // unsupported properties + defineReadProperty('noscreen'); + defineReadProperty('renotify'); + defineReadProperty('sound'); + defineReadProperty('sticky'); + defineReadProperty('vibrate'); + + // event handlers + var defineEventHandler = function(event, callback) { + defineReadProperty(event); + Notification.prototype.__defineSetter__(event, function(originalCallback) { + this.notification[event] = function() { + callbackevent = { + preventDefault: function() { + this.isPrevented = true; + } + }; + if (callback) { + callback(callbackevent); + if (!callbackevent.isPrevented) { + originalCallback(); + } + } + else { + originalCallback(); + } + } + }); + } + defineEventHandler('onclick', eventHandlers.onclick); + defineEventHandler('onerror', eventHandlers.onerror); + + // obsolete handlers + defineEventHandler('onclose', eventHandlers.onclose); + defineEventHandler('onshow', eventHandlers.onshow); + + // static methods + Notification.requestPermission = function(callback) { + OriginalNotification.requestPermission(callback); + }; + + // instance methods + Notification.prototype.close = function() { + this.notification.close(); + }; +} + +module.exports = { + override: override +}; diff --git a/src/browser/webview/mattermost.js b/src/browser/webview/mattermost.js index 859472da..ba9500c4 100644 --- a/src/browser/webview/mattermost.js +++ b/src/browser/webview/mattermost.js @@ -2,7 +2,7 @@ const electron = require('electron'); const ipc = electron.ipcRenderer; -const NativeNotification = Notification; +const notification = require('../js/notification'); var hasClass = function(element, className) { var rclass = /[\t\r\n\f]/g; @@ -107,35 +107,21 @@ function isLowerThanOrEqualWindows8_1() { return (osVersion.major <= 6 && osVersion.minor <= 3); }; -// Show balloon when notified. -function overrideNotificationWithBalloon() { - Notification = function(title, options) { - ipc.send('notified', { - title: title, - options: options - }); - }; - Notification.permission = NativeNotification.permission; - Notification.requestPermission = function(callback) { - callback('granted'); - }; - Notification.prototype.close = function() {}; -}; - -// Show window even if it is hidden/minimized when notification is clicked. -function overrideNotification() { - Notification = function(title, options) { - this.notification = new NativeNotification(title, options); - }; - Notification.permission = NativeNotification.permission; - Notification.requestPermission = function(callback) { - callback('granted'); - }; - Notification.prototype.close = function() { - this.notification.close(); - }; - Notification.prototype.__defineSetter__('onclick', function(callback) { - this.notification.onclick = function() { +if (process.platform === 'win32' && isLowerThanOrEqualWindows8_1()) { + // Show balloon when notified. + notification.override({ + notification: function(title, options) { + ipc.send('notified', { + title: title, + options: options + }); + } + }); +} +else { + // Show window even if it is hidden/minimized when notification is clicked. + notification.override({ + onclick: function() { if (process.platform === 'win32') { // show() breaks Aero Snap state. electron.remote.getCurrentWindow().focus(); @@ -144,14 +130,6 @@ function overrideNotification() { electron.remote.getCurrentWindow().show(); } ipc.sendToHost('onNotificationClick'); - callback(); - }; + } }); } - -if (process.platform === 'win32' && isLowerThanOrEqualWindows8_1()) { - overrideNotificationWithBalloon(); -} -else { - overrideNotification(); -} From 90f9d3ec89ff3a7b4a1b7e32934d26b025dcc719 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 1 Mar 2016 23:32:09 +0900 Subject: [PATCH 09/26] Add missing args --- src/browser/js/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/js/notification.js b/src/browser/js/notification.js index eef0c4be..f893d879 100644 --- a/src/browser/js/notification.js +++ b/src/browser/js/notification.js @@ -4,7 +4,7 @@ function override(eventHandlers) { Notification = function(title, options) { this.notification = new OriginalNotification(title, options); if (eventHandlers.notification) { - eventHandlers.notification(); + eventHandlers.notification(title, options); } }; From 3ea313743dd4b928b661a8087b1b8068c7fda8e4 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Fri, 4 Mar 2016 01:51:34 +0900 Subject: [PATCH 10/26] Add error view when failed to load the URL --- src/browser/index.jsx | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 059da87a..a9e4691f 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -10,6 +10,8 @@ const Col = ReactBootstrap.Col; const Nav = ReactBootstrap.Nav; const NavItem = ReactBootstrap.NavItem; const Badge = ReactBootstrap.Badge; +const ListGroup = ReactBootstrap.ListGroup; +const ListGroupItem = ReactBootstrap.ListGroupItem; const electron = require('electron'); const remote = electron.remote; @@ -204,6 +206,7 @@ var TabBar = React.createClass({ var MattermostView = React.createClass({ getInitialState: function() { return { + did_fail_load: null }; }, handleUnreadCountChange: function(unreadCount, mentionCount, isUnread, isMentioned) { @@ -216,6 +219,13 @@ var MattermostView = React.createClass({ var thisObj = this; var webview = ReactDOM.findDOMNode(this.refs.webview); + webview.addEventListener('did-fail-load', function(e) { + console.log(thisObj.props.name, 'webview did-fail-load', e); + thisObj.setState({ + did_fail_load: e + }); + }); + // Open link in browserWindow. for exmaple, attached files. webview.addEventListener('new-window', function(e) { var currentURL = url.parse(webview.getURL()); @@ -293,7 +303,39 @@ var MattermostView = React.createClass({ // 'disablewebsecurity' is necessary to display external images. // However, it allows also CSS/JavaScript. // So webview should use 'allowDisplayingInsecureContent' as same as BrowserWindow. - return (); + if (this.state.did_fail_load === null) { + return (); + } else { + return () + } + } +}); + +// ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h +var ErrorView = React.createClass({ + render: function() { + return ( + +

Failed to load the URL

+

+ { 'URL: ' } + { this.props.errorInfo.validatedURL } +

+

+ { 'Error code: ' } + { this.props.errorInfo.errorCode } +

+

+ { this.props.errorInfo.errorDescription } +

+

Please check below.

+ + Is your computer online? + Is the server alive? + Is the URL correct? + +
+ ); } }); From 1fad30aed7f906287c71b6acc20ff5a85197c985 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 5 Mar 2016 20:26:13 +0900 Subject: [PATCH 11/26] Fixup messages --- src/browser/index.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/index.jsx b/src/browser/index.jsx index a9e4691f..1740b34e 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -312,6 +312,7 @@ var MattermostView = React.createClass({ }); // ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h +// FIXME: need better wording in English var ErrorView = React.createClass({ render: function() { return ( @@ -328,7 +329,7 @@ var ErrorView = React.createClass({

{ this.props.errorInfo.errorDescription }

-

Please check below.

+

Please check below. Then, reload this window. (Ctrl+R or Command+R)

Is your computer online? Is the server alive? From 1ccb7cebce4e7fb9c285dacc1348c894fa730aef Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 5 Mar 2016 20:52:27 +0900 Subject: [PATCH 12/26] Add test for failed to load URL --- src/browser/index.jsx | 4 ++-- test/browser_test.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 1740b34e..9c10648f 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -306,7 +306,7 @@ var MattermostView = React.createClass({ if (this.state.did_fail_load === null) { return (); } else { - return () + return () } } }); @@ -316,7 +316,7 @@ var MattermostView = React.createClass({ var ErrorView = React.createClass({ render: function() { return ( - +

Failed to load the URL

{ 'URL: ' } diff --git a/test/browser_test.js b/test/browser_test.js index a30ae701..33bb44fb 100644 --- a/test/browser_test.js +++ b/test/browser_test.js @@ -166,6 +166,21 @@ describe('electron-mattermost', function() { }) .end(); }); + + it('should show error when using incorrect URL', function() { + this.timeout(30000) + fs.writeFileSync(config_file_path, JSON.stringify({ + version: 1, + teams: [{ + name: 'error_1', + url: 'http://false' + }] + })); + return client + .init() + .waitForVisible('#mattermostView0-fail', 20000) + .end(); + }); }); describe('settings.html', function() { From f9387d251d9c4088abf3258f496933d8eb647cae Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sun, 6 Mar 2016 14:23:31 +0900 Subject: [PATCH 13/26] Notify the error --- src/browser/index.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 9c10648f..00c7bb83 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -221,6 +221,11 @@ var MattermostView = React.createClass({ webview.addEventListener('did-fail-load', function(e) { console.log(thisObj.props.name, 'webview did-fail-load', e); + // should use permanent way to indicate + var did_fail_load_notification = new Notification(`Failed to load "${thisObj.props.name}"`, { + body: `ErrorCode: ${e.errorCode}`, + icon: '../resources/appicon.png' + }); thisObj.setState({ did_fail_load: e }); From 066672205a8c3c9c8f79913a6cc435b06f10cea2 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sun, 6 Mar 2016 21:58:52 +0900 Subject: [PATCH 14/26] Confirm to trust certificate when there is error For #26 --- src/browser/index.jsx | 4 +++ src/main.js | 33 +++++++++++++++++++ src/main/certificateStore.js | 62 ++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/main/certificateStore.js diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 00c7bb83..c6ecf2b4 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -221,6 +221,10 @@ var MattermostView = React.createClass({ webview.addEventListener('did-fail-load', function(e) { console.log(thisObj.props.name, 'webview did-fail-load', e); + if (e.errorCode === -3) { // An operation was aborted (due to user action). + return; + } + // should use permanent way to indicate var did_fail_load_notification = new Notification(`Failed to load "${thisObj.props.name}"`, { body: `ErrorCode: ${e.errorCode}`, diff --git a/src/main.js b/src/main.js index f2a1b0f1..65763dc0 100644 --- a/src/main.js +++ b/src/main.js @@ -10,6 +10,7 @@ const fs = require('fs'); const path = require('path'); var settings = require('./common/settings'); +var certificateStore = require('./main/certificateStore').load(path.resolve(app.getPath('userData'), 'certificate.json')); var appMenu = require('./main/menus/app'); var argv = require('yargs').argv; @@ -80,6 +81,38 @@ app.on('before-quit', function() { willAppQuit = true; }); +app.on('certificate-error', function(event, webContents, url, error, certificate, callback) { + if (certificateStore.isTrusted(url, certificate)) { + event.preventDefault(); + callback(true); + } + else { + var detail = `URL: ${url}\nError: ${error}`; + if (certificateStore.isExisting(url)) { + detail = `Certificate is different from previous one.\n\n` + detail; + } + + electron.dialog.showMessageBox(mainWindow, { + title: 'Certificate error', + message: `Do you trust certificate from "${certificate.issuerName}"?`, + detail: detail, + type: 'warning', + buttons: [ + 'Yes', + 'No' + ], + cancelId: 1 + }, function(response) { + if (response === 0) { + certificateStore.add(url, certificate); + certificateStore.save(); + webContents.loadURL(url); + } + }); + callback(false); + } +}); + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { diff --git a/src/main/certificateStore.js b/src/main/certificateStore.js new file mode 100644 index 00000000..da091ac6 --- /dev/null +++ b/src/main/certificateStore.js @@ -0,0 +1,62 @@ +'use strict'; + +const fs = require('fs'); +const url = require('url'); + +function comparableCertificate(certificate) { + return { + data: certificate.data.toString(), + issuerName: certificate.issuerName + }; +} + +function areEqual(certificate0, certificate1) { + if (certificate0.data !== certificate1.data) { + return false; + } + if (certificate0.issuerName !== certificate1.issuerName) { + return false; + } + return true; +} + +function getHost(targetURL) { + return url.parse(targetURL).host; +} + +var CertificateStore = function(storeFile) { + this.storeFile = storeFile + try { + this.data = JSON.parse(fs.readFileSync(storeFile, 'utf-8')); + } + catch (e) { + console.log(e); + this.data = {}; + } +}; + +CertificateStore.prototype.save = function() { + fs.writeFileSync(this.storeFile, JSON.stringify(this.data, null, ' ')); +}; + +CertificateStore.prototype.add = function(targetURL, certificate) { + this.data[getHost(targetURL)] = comparableCertificate(certificate); +}; + +CertificateStore.prototype.isExisting = function(targetURL) { + return this.data.hasOwnProperty(getHost(targetURL)); +}; + +CertificateStore.prototype.isTrusted = function(targetURL, certificate) { + var host = getHost(targetURL); + if (!this.isExisting(targetURL)) { + return false; + } + return areEqual(this.data[host], comparableCertificate(certificate)); +}; + +module.exports = { + load: function(storeFile) { + return new CertificateStore(storeFile); + } +}; From 2dc6d1e26d23f578324b27012bff9eec4c513070 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sun, 6 Mar 2016 22:13:30 +0900 Subject: [PATCH 15/26] Update README.md For #26 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5aa8c8de..c1d4079a 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,13 @@ Configuration will be saved into Electron's userData directory: * `~/Library/Application Support/electron-mattermost` on OS X * `~/.config/electron-mattermost` on Linux +### Proxy +You can resolve the proxy by following command line options. +*Note: Authorization is not supported.* + +* `--proxy-server=:` +* `--proxy-pac-url=` + ## Testing and Development Node.js is required to test this app. From f729054f36610c7946dd99b65d653fd5ff49dbc6 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 9 Mar 2016 20:52:00 +0900 Subject: [PATCH 16/26] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c1d4079a..4b42cd29 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,14 @@ Configuration will be saved into Electron's userData directory: * `~/.config/electron-mattermost` on Linux ### Proxy -You can resolve the proxy by following command line options. -*Note: Authorization is not supported.* +Normally, the application will follow your system settings to use proxy. +Or you can set proxy by following command line options. * `--proxy-server=:` * `--proxy-pac-url=` +*Note: Authorization is not supported yet.* + ## Testing and Development Node.js is required to test this app. From 97808373ede7aa333a4dd21de062da8024af5890 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Thu, 10 Mar 2016 23:25:35 +0900 Subject: [PATCH 17/26] Enable "Add" button only when "Name" and "URL" is filled out --- src/browser/settings.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/browser/settings.jsx b/src/browser/settings.jsx index c25e53a8..876be864 100644 --- a/src/browser/settings.jsx +++ b/src/browser/settings.jsx @@ -169,8 +169,8 @@ var TeamListItemNew = React.createClass({ console.log('submit'); e.preventDefault(); this.props.onTeamAdd({ - name: this.state.name, - url: this.state.url + name: this.state.name.trim(), + url: this.state.url.trim() }); this.setState(this.getInitialState()); }, @@ -186,6 +186,9 @@ var TeamListItemNew = React.createClass({ url: e.target.value }); }, + shouldEnableAddButton: function() { + return (this.state.name.trim() !== '') && (this.state.url.trim() !== ''); + }, render: function() { return ( @@ -202,7 +205,7 @@ var TeamListItemNew = React.createClass({ { ' ' } - + ); From 993efb39b638d804cbc017585cf9f3eefdb9ea67 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 16 Mar 2016 20:55:41 +0900 Subject: [PATCH 18/26] Fix crash when freetype 2.6.3 is used in system Fix #76. See https://github.com/atom/electron/issues/4513 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 722c748d..964da9f9 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "del": "^2.2.0", "electron-connect": "^0.3.3", "electron-packager": "^5.1.0", - "electron-prebuilt": "0.36.7", + "electron-prebuilt": "0.36.11", "esformatter": "^0.8.1", "esformatter-jsx": "^4.0.6", "gulp": "^3.9.0", From adc1ebe875dd750db11646c46f6ce006b8ced03c Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Tue, 22 Mar 2016 23:37:59 +0900 Subject: [PATCH 20/26] Update CONTRIBUTING.md --- CONTRIBUTING.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be0aab8e..12b5aeee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,8 +5,8 @@ Thank you for your contributing! My requests are few things. Please read below. Thank you for feedback. When you report a problem, please pay attention to following points. ### Does it happen on web browsers? (especially Chrome) -electron-mattermost is based on Electron. It integrates Chrome as a browser window. -If the problem appears on web browsers, it may be the issue for Mattermost (or Chrome). +Mattermost Desktop is based on Electron. It integrates Chrome as a browser window. +If the problem appears on web browsers, it may be the issue for Mattermost server (or Chrome). ### Try "Clear Cache and Reload" It's available as `Ctrl(Command) + Shift + R`. @@ -14,14 +14,15 @@ Some layout problems are caused by browser cache. Especially, this kind of issue might happen when you have updated Mattermost server. ### Write detailed information -Following points are very helpful to understand the problem. +Detailed information is very helpful to understand the problem. +For example: * How to reproduce, step-by-step * Expected behavior (or what is wrong) * Screenshots (for GUI issues) * Application version * Operating system -* Mattermost version +* Mattermost server version ## Feature idea Please see http://www.mattermost.org/feature-requests/ . @@ -29,10 +30,9 @@ Please see http://www.mattermost.org/feature-requests/ . ## Pull request Pull requests are welcome. Thank you for your great work! -1. When you edit the code, please run `npm run prettify` to format your code before `git commit`. -2. In the description of your pull request, please include: - * Operating System version on which you tested - * Mattermost server version on which you tested - * New or updated unit tests for your changes +1. When you edit the code, please run `npm run prettify` to format your code before `git commit`. +2. In the description of your pull request, please include: + * Operating System version on which you tested + * Mattermost server version on which you tested + * New or updated unit tests for your changes 3. Please complete the [Mattermost CLA](http://www.mattermost.org/mattermost-contributor-agreement/) prior to submitting a PR. - From dcadb4aac41ca3561efb035c7ec8790f572e9499 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 23 Mar 2016 00:29:18 +0900 Subject: [PATCH 21/26] Update CHANGELOG.md for v1.1.0 --- CHANGELOG.md | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 450ebb44..b793c5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,51 @@ # Mattermost Desktop Application Changelog -## IN PROGRESS: Release v1.0.8 (Beta) +## Release v1.1.0 (Beta) The `electron-mattermost` project is now the official desktop application for the Mattermost open source project. + ### Changes -- Renaming project from `electron-mattermost` to `desktop` + +#### All platforms + +- Rename project from `electron-mattermost` to `desktop` +- Rename the executable file from `electron-mattermost` to `Mattermost` + - The configuration directory is also different from previous versions. + - Should execute following command to take over `config.json`. + - Windows: `copy %APPDATA%\electron-mattermost\config.json %APPDATA%\Mattermost\config.json` + - OS X: `cp ~/Library/Application\ Support/electron-mattermost/config.json ~/Library/Application\ Support/Mattermost/config.json` + - Linux: `cp ~/.config/electron-mattermost/config.json ~/.config/Mattermost/config.json` + + +### Improvements + +#### All platforms +- Refine application icon. +- Show error messages when the application failed in loading Mattermost server. +- Show confirmation dialog to continue connection when there is certificate error. +- Add validation to check whether both of **Name** and **URL** fields are not blank. + +#### Windows +- Show a small circle on the tray icon when there are new messages. + ### Fixes -- On **Settings Page** added validation so that **Name** field value is required before team site can be added. + +#### Windows +- **File** > **About** does not bring up version number dialog. + +#### Linux +- **File** > **About** does not bring up version number dialog. +- Ubuntu: Notification is not showing up. +- The view crashes when freetype 2.6.3 is used in system. + ### Known issues -- Windows and Linux: **File** > **About** does not bring up version number dialog -- Windows: Application does not appear in Windows volume mixer -- All platforms: Embedded markdown images with `http://` do not render +#### All platforms +- Images with `http://` do not render. +- Basic Authentication is not working. + +#### Windows +- Application does not appear properly in Windows volume mixer. From e72573d787623a1ff5a391cda1d216040b553960 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 23 Mar 2016 01:14:17 +0900 Subject: [PATCH 22/26] Add a known issue to CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b793c5f9..6312ab6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ The `electron-mattermost` project is now the official desktop application for th #### All platforms - Images with `http://` do not render. - Basic Authentication is not working. +- Some keyboard shortcuts are missing. (e.g. Ctrl+W, Command+,) #### Windows - Application does not appear properly in Windows volume mixer. From e3130e4c77a8463040400885261e03b7c0670b59 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 23 Mar 2016 01:51:27 +0900 Subject: [PATCH 23/26] Update version to 1.1.0 --- package.json | 2 +- src/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 19556374..3492d439 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mattermost-desktop", "productName": "Mattermost", - "version": "1.0.7", + "version": "1.1.0", "description": "Mattermost Desktop application for Windows, Mac and Linux", "main": "main.js", "author": "Yuya Ochiai", diff --git a/src/package.json b/src/package.json index cc9f27d7..605f03d8 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "mattermost-desktop", "productName": "Mattermost", - "version": "1.0.7", + "version": "1.1.0", "description": "Mattermost Desktop application for Windows, Mac and Linux", "main": "main.js", "author": "Yuya Ochiai", From 89959c7c93a1ad47e95f8c0bbb6efbd4c063f32f Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 23 Mar 2016 22:50:12 +0900 Subject: [PATCH 24/26] Update CONTRIBUTING.md from @lloeki's suggestion in #92 --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12b5aeee..709c4665 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,8 +5,8 @@ Thank you for your contributing! My requests are few things. Please read below. Thank you for feedback. When you report a problem, please pay attention to following points. ### Does it happen on web browsers? (especially Chrome) -Mattermost Desktop is based on Electron. It integrates Chrome as a browser window. -If the problem appears on web browsers, it may be the issue for Mattermost server (or Chrome). +Mattermost Desktop is based on Electron, which integrates the Chrome engine within a standalone application. +If the problem you encounter can be reproduced on web browsers, it may be an issue with Mattermost server (or Chrome). ### Try "Clear Cache and Reload" It's available as `Ctrl(Command) + Shift + R`. From 7e7109413307336af211c4d19bbb4a280a470644 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 23 Mar 2016 23:04:03 +0900 Subject: [PATCH 25/26] Fix pixelated taskbar icon on HiDPI Windows --- src/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index f443a43f..94c07baa 100644 --- a/src/main.js +++ b/src/main.js @@ -163,7 +163,8 @@ app.on('ready', function() { // follow Electron's defaults window_options = {}; } - if (process.platform === 'linux') { + if (process.platform === 'win32' || process.platform === 'linux') { + // On HiDPI Windows environment, the taskbar icon is pixelated. So this line is necessary. window_options.icon = path.resolve(__dirname, 'resources/appicon.png'); } window_options.fullScreenable = true; From 55e57412cc23b76ec7981ee2b3bc25ac5e238a40 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Wed, 30 Mar 2016 20:56:47 +0900 Subject: [PATCH 26/26] Update README.md for basic auth --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6312ab6e..3b8621cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The `electron-mattermost` project is now the official desktop application for th - Show error messages when the application failed in loading Mattermost server. - Show confirmation dialog to continue connection when there is certificate error. - Add validation to check whether both of **Name** and **URL** fields are not blank. +- Add simple basic HTTP authentication (requires a command line). #### Windows - Show a small circle on the tray icon when there are new messages. @@ -47,6 +48,7 @@ The `electron-mattermost` project is now the official desktop application for th - Images with `http://` do not render. - Basic Authentication is not working. - Some keyboard shortcuts are missing. (e.g. Ctrl+W, Command+,) +- Basic authentication requires a command line. #### Windows - Application does not appear properly in Windows volume mixer.