Merge branch 'master' into auto-updater

This commit is contained in:
Yuya Ochiai
2018-12-19 23:21:01 +09:00
24 changed files with 2902 additions and 3940 deletions

View File

@@ -1,12 +0,0 @@
{
"presets": [
["env", {
"targets": {
"browsers": ["Electron >= 1.8"],
"node": "8.2"
}
}],
"react"
],
"plugins": ["transform-object-rest-spread", "transform-class-properties"]
}

View File

@@ -12,45 +12,69 @@ Release date: TBD
### Improvements ### Improvements
### Architectural Changes
- Major version upgrade of Electron to v3.0.10. Electron is the underlying technology used to build the Desktop apps.
[#892](https://github.com/mattermost/desktop/pull/892)
### Bug Fixes
- Fixed several typos.
[#905](https://github.com/mattermost/desktop/pull/905)
----
## Release v4.2.0
Release date: Nov 27, 2018
- Mattermost v4.2.0 contains a high level security fix. [Upgrading](http://docs.mattermost.com/administration/upgrade.html) is highly recommended. Details will be posted on our [security updates page](https://about.mattermost.com/security-updates/) 30 days after release as per the [Mattermost Responsible Disclosure Policy](https://www.mattermost.org/responsible-disclosure-policy/).
### Improvements
#### All Platforms #### All Platforms
- Added Portuguese spell checker - Added English (UK), Portuguese (BR), Spanish (ES) and Spanish (MX) to the spell checker.
[#843](https://github.com/mattermost/desktop/pull/843) [#843](https://github.com/mattermost/desktop/pull/843)
[#875](https://github.com/mattermost/desktop/pull/875)
- Added `Ctrl/Cmd+F` shortcut to work as browser-like search. - Added `Ctrl/Cmd+F` shortcut to work as browser-like search.
[#399](https://github.com/mattermost/desktop/issues/399) [#399](https://github.com/mattermost/desktop/issues/399)
- Preserved case of first letter in spellcheck. - Preserved case of first letter in spellcheck.
[#869](https://github.com/mattermost/desktop/pull/869) [#869](https://github.com/mattermost/desktop/pull/869)
- Added support for session expiry notification.
[#866](https://github.com/mattermost/desktop/pull/866)
#### Windows #### Windows
- Set "app start on login" preference to default on and synchronize its state with config.json. - Set "app start on login" preference as enabled by default and synchronized its state with config.json.
[#846](https://github.com/mattermost/desktop/pull/846) [#846](https://github.com/mattermost/desktop/pull/846)
- Removed the ability to open UNC path and file:// links.
[#881](https://github.com/mattermost/desktop/pull/881)
#### Mac #### Mac
- Add **.dmg** package to support installation. - Added **.dmg** package to support installation.
[#588](https://github.com/mattermost/desktop/pull/588) [#588](https://github.com/mattermost/desktop/pull/588)
- Support "Hide" option of Login Items in Preferences. - Added "Hide" option to Login Items in Preferences.
[#853](https://github.com/mattermost/desktop/pull/853) [#853](https://github.com/mattermost/desktop/pull/853)
#### Linux #### Linux
- [tar.gz] Use SVG icon for Linux application menus in place of PNG icon - [tar.gz] Added support for using SVG icons for Linux application menus in place of PNG icons.
[#815](https://github.com/mattermost/desktop/pull/815) [#815](https://github.com/mattermost/desktop/pull/815)
- Updated categories in order to be listed under the appropriate submenu of the application starter. - Updated categories in order to be listed under the appropriate submenu of the application starter.
[#816](https://github.com/mattermost/desktop/pull/816) [#816](https://github.com/mattermost/desktop/pull/816)
[#818](https://github.com/mattermost/desktop/pull/818) [#818](https://github.com/mattermost/desktop/pull/818)
- Set "app start on login" preference to default on and synchronize its state with config.json. - Set "app start on login" preference as enabled by default and synchronized its state with config.json.
[#846](https://github.com/mattermost/desktop/pull/846) [#846](https://github.com/mattermost/desktop/pull/846)
- Added AppImage packages as unofficial build - Added AppImage packages as an unofficial build.
[#864](https://github.com/mattermost/desktop/pull/864) [#864](https://github.com/mattermost/desktop/pull/864)
### Architectural Changes ### Architectural Changes
- Major version upgrade of Electron to v2.0.8. Electron is the underlying technology used to build the Desktop apps. - Major version upgrade of Electron to v2.0.12. Electron is the underlying technology used to build the Desktop apps.
[#820](https://github.com/mattermost/desktop/pull/820) [#820](https://github.com/mattermost/desktop/pull/820)
[#847](https://github.com/mattermost/desktop/pull/847) [#847](https://github.com/mattermost/desktop/pull/847)
- Artifact names are configured via `electron-builder.json`. [#882](https://github.com/mattermost/desktop/pull/882)
- Artifact names are now configured via `electron-builder.json`.
[#825](https://github.com/mattermost/desktop/pull/825) [#825](https://github.com/mattermost/desktop/pull/825)
### Bug Fixes ### Contributors
Many thanks to all our contributors. In alphabetical order:
- [danmaas](https://github.com/danmaas), [hmhealey](https://github.com/hmhealey), [j1mc](https://github.com/j1mc),[jasonblais](https://github.com/jasonblais), [lieut-data](https://github.com/lieut-data), [rodcorsi](https://github.com/rodcorsi), [scherno2](https://github.com/scherno2), [sudheerDev](https://github.com/sudheerDev), [svelle](https://github.com/svelle), [torlenor](https://github.com/torlenor), [yuya-oc](https://github.com/yuya-oc)
---- ----

View File

@@ -56,7 +56,7 @@ The most popular front-end framework for developing responsive, mobile first pro
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2011-2016 Twitter, Inc. Copyright (c) 2011-2018 Twitter, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -514,7 +514,7 @@ A react component toolset for managing animations
BSD 3-Clause License BSD 3-Clause License
Copyright (c) 2016, React Community Copyright (c) 2018, React Community
Forked from React (https://github.com/facebook/react) Copyright 2013-present, Facebook, Inc. Forked from React (https://github.com/facebook/react) Copyright 2013-present, Facebook, Inc.
All rights reserved. All rights reserved.

19
babel.config.js Normal file
View File

@@ -0,0 +1,19 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
module.exports = (api) => { // eslint-disable-line import/no-commonjs
api.cache.forever();
return {
presets: [
['@babel/preset-env', {
targets: {
browsers: ['Electron >= 2.0'],
node: '8.9',
},
}],
'@babel/preset-react',
],
plugins: ['@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-class-properties'],
};
};

View File

@@ -76,7 +76,7 @@ Test coding style:
$ npm run lint:js $ npm run lint:js
``` ```
### Helper commmands ### Helper commands
#### `npm run watch` #### `npm run watch`
Reload the application automatically when you have saved source codes. Reload the application automatically when you have saved source codes.

View File

@@ -61,7 +61,7 @@ Pre-work for the current release begins at the code complete date of the previou
- Post links to final tickets for next RC to the Desktop App channel - Post links to final tickets for next RC to the Desktop App channel
- Submit PRs for hotfixes against the release branch, and review, test and merge prior to next RC - Submit PRs for hotfixes against the release branch, and review, test and merge prior to next RC
4. Build: 4. Build:
- Push next RC to acceptance and announce in Destkop App channel with new RC link - Push next RC to acceptance and announce in Desktop App channel with new RC link
5. PM: 5. PM:
- Test the new RC to verify fixes merged to the release branch work and post in Desktop App channel after testing - Test the new RC to verify fixes merged to the release branch work and post in Desktop App channel after testing
- Update the meta issue with download links to the new RCs and a list of approved fixes - Update the meta issue with download links to the new RCs and a list of approved fixes
@@ -152,4 +152,4 @@ If a bug fix release is required, run through the following steps:
- Post and review [Mattermost Security Updates](https://about.mattermost.com/security-updates/) for the Desktop App - Post and review [Mattermost Security Updates](https://about.mattermost.com/security-updates/) for the Desktop App
- Update Security Issues spreadsheet with issue number from posted update (e.g. v3.2.0.1) - Update Security Issues spreadsheet with issue number from posted update (e.g. v3.2.0.1)
- Confirm the Security Researchers list on the [Responsible Disclosure Policy](https://www.mattermost.org/responsible-disclosure-policy/) is up to date - Confirm the Security Researchers list on the [Responsible Disclosure Policy](https://www.mattermost.org/responsible-disclosure-policy/) is up to date
- Review community installers for the Desktop App and update version numbers if there are any discrepencies https://www.mattermost.org/installation/ - Review community installers for the Desktop App and update version numbers if there are any discrepancies https://www.mattermost.org/installation/

View File

@@ -105,7 +105,7 @@ The Mattermost desktop application offers:
- Icon notifications from Windows Task Bar - Icon notifications from Windows Task Bar
- Desktop notifications - Desktop notifications
See the Mattermost [help documention](http://docs.mattermost.com/help/getting-started/signing-in.html) for how to use the Mattermost team site. See the Mattermost [help documentation](http://docs.mattermost.com/help/getting-started/signing-in.html) for how to use the Mattermost team site.
## Settings Page ## Settings Page
@@ -121,7 +121,7 @@ The Settings Page is available from the **File** menu under **Settings** (Click
- **Hide Menu Bar** (Windows, Linux) - **Hide Menu Bar** (Windows, Linux)
- This option hides the menu bar. Press "Alt" to show it. - This option hides the menu bar. Press "Alt" to show it.
- **Show Icon on Menu Bar** (OS X) - **Show Icon on Menu Bar** (OS X)
- The icon apeears on menu bar to indicate whether there are new messages or mention. - The icon appears on menu bar to indicate whether there are new messages or mention.
- **Allow insecure contents** - **Allow insecure contents**
- If your team is hosted on `https://`, images with `http://` are not rendered by default. - If your team is hosted on `https://`, images with `http://` are not rendered by default.
This option allows such images to be rendered, but please be careful for security. This option allows such images to be rendered, but please be careful for security.
@@ -180,7 +180,7 @@ Below lists menu options (shortcut keys are listed in brackets, `Ctrl` becomes `
Mattermost lets users configure [desktop notifications](http://docs.mattermost.com/help/getting-started/configuring-notifications.html#desktop-notifications) to alert users to new events in a team site. Mattermost lets users configure [desktop notifications](http://docs.mattermost.com/help/getting-started/configuring-notifications.html#desktop-notifications) to alert users to new events in a team site.
For the Mattermost Windows application, these appear as ballon notifications from the task bar on Windows 7 and Windows 8.1, and as a "toast" pop-up on Windows 10. For the Mattermost Windows application, these appear as balloon notifications from the task bar on Windows 7 and Windows 8.1, and as a "toast" pop-up on Windows 10.
## Start Menu and Task Bar shortcuts (Windows) ## Start Menu and Task Bar shortcuts (Windows)

View File

@@ -1,7 +1,7 @@
{ {
"name": "mattermost-desktop", "name": "mattermost-desktop",
"productName": "Mattermost", "productName": "Mattermost",
"version": "4.2.0-develop", "version": "4.3.0-develop",
"description": "Mattermost", "description": "Mattermost",
"main": "main.js", "main": "main.js",
"author": "Mattermost, Inc. <feedback@mattermost.com>", "author": "Mattermost, Inc. <feedback@mattermost.com>",
@@ -26,29 +26,32 @@
"watch:main": "node scripts/watch_main_and_preload.js", "watch:main": "node scripts/watch_main_and_preload.js",
"watch:renderer": "webpack-dev-server --config webpack.config.renderer.js", "watch:renderer": "webpack-dev-server --config webpack.config.renderer.js",
"test": "npm-run-all test:* lint:*", "test": "npm-run-all test:* lint:*",
"test:app": "cross-env NODE_ENV=production npm run build && mocha -r babel-register --reporter mocha-circleci-reporter --recursive test/specs", "test:app": "cross-env NODE_ENV=production npm run build && mocha -r @babel/register --reporter mocha-circleci-reporter --recursive test/specs",
"package:all": "cross-env NODE_ENV=production npm-run-all check-build-config package:windows package:mac package:linux", "package:all": "cross-env NODE_ENV=production npm-run-all check-build-config package:windows package:mac package:linux",
"package:windows": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --win --x64 --ia32 --publish=never", "package:windows": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --win --x64 --ia32 --publish=never",
"package:mac": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --mac --publish=never", "package:mac": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --mac --publish=never",
"package:linux": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --linux --x64 --ia32 --publish=never", "package:linux": "cross-env NODE_ENV=production npm-run-all check-build-config build && build --linux --x64 --ia32 --publish=never",
"lint:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --ext .js --ext .jsx .", "lint:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --ext .js --ext .jsx .",
"fix:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --quiet --ext .js --ext .jsx . --fix", "fix:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --quiet --ext .js --ext .jsx . --fix",
"check-build-config": "node -r babel-register scripts/check_build_config.js" "check-build-config": "node -r @babel/register scripts/check_build_config.js"
}, },
"devDependencies": { "devDependencies": {
"7zip-bin": "^4.0.2", "7zip-bin": "^4.0.2",
"@storybook/react": "^3.4.6", "@babel/core": "^7.1.6",
"babel-core": "^6.26.3", "@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/preset-env": "^7.1.6",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.0.0",
"@storybook/addon-actions": "^4.0.9",
"@storybook/react": "^4.0.9",
"babel-eslint": "^8.2.3", "babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4", "babel-loader": "^8.0.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"chai": "^4.1.2", "chai": "^4.1.2",
"cross-env": "^5.1.6", "cross-env": "^5.1.6",
"css-loader": "^0.28.11", "css-loader": "^1.0.1",
"devtron": "^1.4.0", "devtron": "^1.4.0",
"electron": "2.0.8", "electron": "^3.0.10",
"electron-builder": "20.14.7", "electron-builder": "20.14.7",
"electron-builder-squirrel-windows": "~20.14.0", "electron-builder-squirrel-windows": "~20.14.0",
"electron-connect": "^0.6.3", "electron-connect": "^0.6.3",
@@ -56,18 +59,18 @@
"eslint-plugin-header": "^1.2.0", "eslint-plugin-header": "^1.2.0",
"eslint-plugin-import": "^2.12.0", "eslint-plugin-import": "^2.12.0",
"eslint-plugin-react": "^7.8.2", "eslint-plugin-react": "^7.8.2",
"file-loader": "^1.1.6", "file-loader": "^2.0.0",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"mocha-circleci-reporter": "0.0.3", "mocha-circleci-reporter": "0.0.3",
"npm-run-all": "^4.1.3", "npm-run-all": "^4.1.3",
"react": "^16.4.0", "react": "^16.4.0",
"react-dom": "^16.4.0", "react-dom": "^16.4.0",
"spectron": "~3.8.0", "spectron": "^5.0.0",
"style-loader": "^0.21.0", "style-loader": "^0.23.1",
"url-loader": "^1.0.1", "url-loader": "^1.1.2",
"webpack": "^4.8.3", "webpack": "^4.26.1",
"webpack-cli": "^2.1.4", "webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.4", "webpack-dev-server": "^3.1.10",
"webpack-merge": "^4.1.2" "webpack-merge": "^4.1.4"
} }
} }

View File

@@ -5,8 +5,8 @@ VERSION=`cat package.json | jq -r '.version'`
SRC=$1 SRC=$1
DEST=$2 DEST=$2
cp "${SRC}/mattermost-desktop-${VERSION}-win-ia32.zip" "${DEST}/" cp "${SRC}/mattermost-desktop-${VERSION}-win-ia32.zip" "${DEST}/mattermost-desktop-${VERSION}-win32.zip"
cp "${SRC}/mattermost-desktop-${VERSION}-win-x64.zip" "${DEST}/" cp "${SRC}/mattermost-desktop-${VERSION}-win-x64.zip" "${DEST}/mattermost-desktop-${VERSION}-win64.zip"
cp "${SRC}/mattermost-desktop-setup-${VERSION}-win.exe" "${DEST}/" cp "${SRC}/mattermost-desktop-setup-${VERSION}-win.exe" "${DEST}/"
cp "${SRC}"/mattermost-desktop-*.zip "${DEST}/" cp "${SRC}"/mattermost-desktop-*.zip "${DEST}/"
cp "${SRC}"/*.tar.gz "${DEST}/" cp "${SRC}"/*.tar.gz "${DEST}/"

View File

@@ -4,7 +4,7 @@ set -eu
function print_link() { function print_link() {
local URL="${1}" local URL="${1}"
local CHECKSUM="$(curl -s -S -L "${URL}" | sha256sum | awk '{print $1}')" local CHECKSUM="$(curl -s -S -L "${URL}" | sha256sum | awk '{print $1}')"
echo "${URL}" echo "- ${URL}"
echo " - SHA-256 Checksum: \`${CHECKSUM}\`" echo " - SHA-256 Checksum: \`${CHECKSUM}\`"
} }
@@ -15,18 +15,26 @@ cat <<-MD
### Mattermost Desktop ${VERSION} has been cut! ### Mattermost Desktop ${VERSION} has been cut!
The download links can be found below. The download links can be found below.
#### Windows
$(print_link "${BASE_URL}/mattermost-setup-${VERSION}-win32.exe")
$(print_link "${BASE_URL}/mattermost-setup-${VERSION}-win64.exe")
#### Windows - zip files
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-win32.zip")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-win64.zip")
#### Mac
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-mac.dmg")
#### Linux #### Linux
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-ia32.tar.gz") $(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-ia32.tar.gz")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-x64.tar.gz") $(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-x64.tar.gz")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-amd64.deb")
#### Linux (Unofficial) - deb files
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-i386.deb") $(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-i386.deb")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-amd64.deb")
#### Mac #### Linux (Unofficial) - AppImage files
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-osx.tar.gz") $(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-i386.AppImage")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-x86_64.AppImage")
#### Windows
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-win32.zip")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-win64.zip")
$(print_link "${BASE_URL}/mattermost-setup-${VERSION}-win32.exe")
$(print_link "${BASE_URL}/mattermost-setup-${VERSION}-win64.exe")
MD MD

1
src/.storybook/addons.js Normal file
View File

@@ -0,0 +1 @@
import '@storybook/addon-actions/register';

View File

@@ -1,7 +1,18 @@
const path = require("path"); const path = require("path");
const rendererConfig = require('../../webpack.config.renderer');
// https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode--default // https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode--default
module.exports = (baseConfig, env, defaultConfig) => { module.exports = (storybookBaseConfig, configType) => {
defaultConfig.resolve.modules = [path.resolve(__dirname, '../node_modules'), 'node_modules']; // Avoid conflicting two instances of React due to two package.json structure
return defaultConfig; storybookBaseConfig.resolve.modules.unshift(path.resolve(__dirname, '../node_modules'));
// Use same rules
storybookBaseConfig.module.rules = rendererConfig.module.rules.concat({
test: /\.(ttf|woff2?|eot|svg)/,
use: {
loader: 'file-loader'
}
});
return storybookBaseConfig;
} }

View File

@@ -77,7 +77,7 @@ export default class MainPage extends React.Component {
}); });
}); });
// can't switch tabs sequencially for some reason... // can't switch tabs sequentially for some reason...
ipcRenderer.on('switch-tab', (event, key) => { ipcRenderer.on('switch-tab', (event, key) => {
this.handleSelect(key); this.handleSelect(key);
}); });

View File

@@ -85,7 +85,7 @@ export default class MattermostView extends React.Component {
} }
}); });
// Open link in browserWindow. for exmaple, attached files. // Open link in browserWindow. for example, attached files.
webview.addEventListener('new-window', (e) => { webview.addEventListener('new-window', (e) => {
const currentURL = url.parse(webview.getURL()); const currentURL = url.parse(webview.getURL());
const destURL = url.parse(e.url); const destURL = url.parse(e.url);
@@ -98,7 +98,7 @@ export default class MattermostView extends React.Component {
if (destURL.path.match(/^\/api\/v[3-4]\/public\/files\//)) { if (destURL.path.match(/^\/api\/v[3-4]\/public\/files\//)) {
ipcRenderer.send('download-url', e.url); ipcRenderer.send('download-url', e.url);
} else { } else {
// New window should disable nodeIntergration. // New window should disable nodeIntegration.
window.open(e.url, remote.app.getName(), 'nodeIntegration=no, show=yes'); window.open(e.url, remote.app.getName(), 'nodeIntegration=no, show=yes');
} }
} else { } else {
@@ -119,7 +119,7 @@ export default class MattermostView extends React.Component {
if (this.props.onSelectSpellCheckerLocale) { if (this.props.onSelectSpellCheckerLocale) {
this.props.onSelectSpellCheckerLocale(locale); this.props.onSelectSpellCheckerLocale(locale);
} }
webview.send('set-spellcheker'); webview.send('set-spellchecker');
}, },
}); });
this.setState({isContextMenuAdded: true}); this.setState({isContextMenuAdded: true});

View File

@@ -22,12 +22,14 @@ function getSuggestionsMenus(win, suggestions) {
function getSpellCheckerLocaleMenus(onSelectSpellCheckerLocale) { function getSpellCheckerLocaleMenus(onSelectSpellCheckerLocale) {
const currentLocale = ipcRenderer.sendSync('get-spellchecker-locale'); const currentLocale = ipcRenderer.sendSync('get-spellchecker-locale');
const locales = [ const locales = [
{language: 'English (UK)', locale: 'en-GB'},
{language: 'English (US)', locale: 'en-US'}, {language: 'English (US)', locale: 'en-US'},
{language: 'French', locale: 'fr-FR'}, {language: 'French', locale: 'fr-FR'},
{language: 'German', locale: 'de-DE'}, {language: 'German', locale: 'de-DE'},
{language: 'Spanish', locale: 'es-ES'}, {language: 'Portuguese (BR)', locale: 'pt-BR'},
{language: 'Spanish (ES)', locale: 'es-ES'},
{language: 'Spanish (MX)', locale: 'es-MX'},
{language: 'Dutch', locale: 'nl-NL'}, {language: 'Dutch', locale: 'nl-NL'},
{language: 'Portuguese', locale: 'pt-BR'},
]; ];
return locales.map((l) => ({ return locales.map((l) => ({
label: l.language, label: l.language,

View File

@@ -141,7 +141,7 @@ function getUnreadCount() {
const activeChannel = document.querySelector('.active .sidebar-channel'); const activeChannel = document.querySelector('.active .sidebar-channel');
const closeButton = activeChannel.getElementsByClassName('btn-close'); const closeButton = activeChannel.getElementsByClassName('btn-close');
if (closeButton.length === 1 && closeButton[0].getAttribute('aria-describedby') === 'remove-dm-tooltip') { if (closeButton.length === 1 && closeButton[0].getAttribute('aria-describedby') === 'remove-dm-tooltip') {
// If active channel is DM, all posts is treated as menion. // If active channel is DM, all posts is treated as mention.
isMentioned = true; isMentioned = true;
break; break;
} else { } else {
@@ -192,7 +192,7 @@ function setSpellChecker() {
resetMisspelledState(); resetMisspelledState();
} }
setSpellChecker(); setSpellChecker();
ipcRenderer.on('set-spellcheker', setSpellChecker); ipcRenderer.on('set-spellchecker', setSpellChecker);
// mattermost-webapp is SPA. So cache is not cleared due to no navigation. // mattermost-webapp is SPA. So cache is not cleared due to no navigation.
// We needed to manually clear cache to free memory in long-term-use. // We needed to manually clear cache to free memory in long-term-use.

View File

@@ -174,14 +174,19 @@ const trayImages = (() => {
} }
})(); })();
// If there is already an instance, activate the window in the existing instace and quit this one // If there is already an instance, activate the window in the existing instance and quit this one
if (app.makeSingleInstance((commandLine/*, workingDirectory*/) => { const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.exit();
global.willAppQuit = true;
}
app.on('second-instance', (event, secondArgv) => {
// Protocol handler for win32 // Protocol handler for win32
// argv: An array of the second instances (command line / deep linked) arguments // argv: An array of the second instances (command line / deep linked) arguments
if (process.platform === 'win32') { if (process.platform === 'win32') {
// Keep only command line / deep linked arguments // Keep only command line / deep linked arguments
if (Array.isArray(commandLine.slice(1)) && commandLine.slice(1).length > 0) { if (Array.isArray(secondArgv.slice(1)) && secondArgv.slice(1).length > 0) {
setDeeplinkingUrl(commandLine.slice(1)[0]); setDeeplinkingUrl(secondArgv.slice(1)[0]);
mainWindow.webContents.send('protocol-deeplink', deeplinkingUrl); mainWindow.webContents.send('protocol-deeplink', deeplinkingUrl);
} }
} }
@@ -194,9 +199,7 @@ if (app.makeSingleInstance((commandLine/*, workingDirectory*/) => {
mainWindow.show(); mainWindow.show();
} }
} }
})) { });
app.exit();
}
function shouldShowTrayIcon() { function shouldShowTrayIcon() {
if (process.platform === 'win32') { if (process.platform === 'win32') {
@@ -328,7 +331,7 @@ app.on('certificate-error', (event, webContents, url, error, certificate, callba
}); });
app.on('gpu-process-crashed', (event, killed) => { app.on('gpu-process-crashed', (event, killed) => {
console.log(`The GPU process has crached (killed = ${killed})`); console.log(`The GPU process has crashed (killed = ${killed})`);
}); });
const loginCallbackMap = new Map(); const loginCallbackMap = new Map();

View File

@@ -2,7 +2,7 @@
"name": "mattermost-desktop", "name": "mattermost-desktop",
"productName": "Mattermost", "productName": "Mattermost",
"desktopName": "Mattermost.desktop", "desktopName": "Mattermost.desktop",
"version": "4.2.0-develop", "version": "4.3.0-develop",
"description": "Mattermost", "description": "Mattermost",
"main": "main_bundle.js", "main": "main_bundle.js",
"author": "Mattermost, Inc. <feedback@mattermost.com>", "author": "Mattermost, Inc. <feedback@mattermost.com>",

16
test/modules/utils.js Normal file
View File

@@ -0,0 +1,16 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
function asyncSleep(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
module.exports = {
asyncSleep,
};

View File

@@ -75,7 +75,7 @@ describe('application', function desc() {
url: env.mattermostURL, url: env.mattermostURL,
})); }));
await this.app.restart(); await this.app.restart();
await this.app.client.waitUntilWindowLoaded();
const url = await this.app.client.getUrl(); const url = await this.app.client.getUrl();
url.should.match(/\/index.html$/); url.should.match(/\/index.html$/);
}); });
@@ -86,7 +86,6 @@ describe('application', function desc() {
url: env.mattermostURL, url: env.mattermostURL,
})); }));
await this.app.restart(); await this.app.restart();
await this.app.client.waitUntilWindowLoaded();
const url = await this.app.client.getUrl(); const url = await this.app.client.getUrl();
url.should.match(/\/index.html$/); url.should.match(/\/index.html$/);

View File

@@ -8,6 +8,7 @@ const http = require('http');
const path = require('path'); const path = require('path');
const env = require('../../modules/environment'); const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils');
describe('browser/index.html', function desc() { describe('browser/index.html', function desc() {
this.timeout(30000); this.timeout(30000);
@@ -35,10 +36,11 @@ describe('browser/index.html', function desc() {
this.server = http.createServer(serverCallback).listen(serverPort, '127.0.0.1'); this.server = http.createServer(serverCallback).listen(serverPort, '127.0.0.1');
}); });
beforeEach(() => { beforeEach(async () => {
fs.writeFileSync(env.configFilePath, JSON.stringify(config)); fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = env.getSpectronApp(); this.app = env.getSpectronApp();
return this.app.start(); await this.app.start();
}); });
afterEach(async () => { afterEach(async () => {
@@ -56,15 +58,12 @@ describe('browser/index.html', function desc() {
url: env.mattermostURL, url: env.mattermostURL,
})); }));
await this.app.restart(); await this.app.restart();
await this.app.client.waitUntilWindowLoaded();
const existing = await this.app.client.isExisting('#tabBar'); const existing = await this.app.client.isExisting('#tabBar');
existing.should.be.false; existing.should.be.false;
}); });
it('should set src of webview from config file', async () => { it('should set src of webview from config file', async () => {
await this.app.client.waitUntilWindowLoaded();
const src0 = await this.app.client.getAttribute('#mattermostView0', 'src'); const src0 = await this.app.client.getAttribute('#mattermostView0', 'src');
src0.should.equal(config.teams[0].url); src0.should.equal(config.teams[0].url);
@@ -76,8 +75,6 @@ describe('browser/index.html', function desc() {
}); });
it('should set name of tab from config file', async () => { it('should set name of tab from config file', async () => {
await this.app.client.waitUntilWindowLoaded();
const tabName0 = await this.app.client.getText('#teamTabItem0'); const tabName0 = await this.app.client.getText('#teamTabItem0');
tabName0.should.equal(config.teams[0].name); tabName0.should.equal(config.teams[0].name);
@@ -86,7 +83,7 @@ describe('browser/index.html', function desc() {
}); });
it('should show only the selected team', () => { it('should show only the selected team', () => {
return this.app.client.waitUntilWindowLoaded(). return this.app.client.
waitForVisible('#mattermostView0', 2000). waitForVisible('#mattermostView0', 2000).
waitForVisible('#mattermostView1', 2000, true). waitForVisible('#mattermostView1', 2000, true).
click('#teamTabItem1'). click('#teamTabItem1').
@@ -104,7 +101,7 @@ describe('browser/index.html', function desc() {
}], }],
})); }));
await this.app.restart(); await this.app.restart();
return this.app.client.waitUntilWindowLoaded(). return this.app.client.
waitForVisible('#mattermostView0-fail', 20000); waitForVisible('#mattermostView0-fail', 20000);
}); });
@@ -117,7 +114,7 @@ describe('browser/index.html', function desc() {
}], }],
})); }));
await this.app.restart(); await this.app.restart();
await this.app.client.waitUntilWindowLoaded().pause(2000); await this.app.client.pause(2000);
const windowTitle = await this.app.browserWindow.getTitle(); const windowTitle = await this.app.browserWindow.getTitle();
windowTitle.should.equal('Mattermost Desktop testing html'); windowTitle.should.equal('Mattermost Desktop testing html');
}); });
@@ -135,7 +132,7 @@ describe('browser/index.html', function desc() {
}], }],
})); }));
await this.app.restart(); await this.app.restart();
await this.app.client.waitUntilWindowLoaded().pause(500); await this.app.client.pause(500);
// Note: Indices of webview are correct. // Note: Indices of webview are correct.
// Somehow they are swapped. // Somehow they are swapped.
@@ -174,7 +171,7 @@ describe('browser/index.html', function desc() {
// Note: Indices of webview are correct. // Note: Indices of webview are correct.
// Somehow they are swapped. // Somehow they are swapped.
await this.app.client.waitUntilWindowLoaded().pause(500); await this.app.client.pause(500);
await this.app.client. await this.app.client.
windowByIndex(2). windowByIndex(2).
@@ -198,7 +195,6 @@ describe('browser/index.html', function desc() {
it('should open the new server prompt after clicking the add button', async () => { it('should open the new server prompt after clicking the add button', async () => {
// See settings_test for specs that cover the actual prompt // See settings_test for specs that cover the actual prompt
await this.app.client.waitUntilWindowLoaded();
await this.app.client.click('#addServerButton').pause(500); await this.app.client.click('#addServerButton').pause(500);
const isModalExisting = await this.app.client.isExisting('#newServerModal'); const isModalExisting = await this.app.client.isExisting('#newServerModal');
isModalExisting.should.be.true; isModalExisting.should.be.true;

View File

@@ -6,6 +6,7 @@
const fs = require('fs'); const fs = require('fs');
const env = require('../../modules/environment'); const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils');
describe('browser/settings.html', function desc() { describe('browser/settings.html', function desc() {
this.timeout(30000); this.timeout(30000);
@@ -21,10 +22,11 @@ describe('browser/settings.html', function desc() {
}], }],
}; };
beforeEach(() => { beforeEach(async () => {
fs.writeFileSync(env.configFilePath, JSON.stringify(config)); fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = env.getSpectronApp(); this.app = env.getSpectronApp();
return this.app.start(); await this.app.start();
}); });
afterEach(async () => { afterEach(async () => {
@@ -34,7 +36,7 @@ describe('browser/settings.html', function desc() {
}); });
describe('Close button', async () => { describe('Close button', async () => {
it('should show index.html when it\'s clicked', async () => { it.skip('should show index.html when it\'s clicked', async () => {
env.addClientCommands(this.app.client); env.addClientCommands(this.app.client);
await this.app.client. await this.app.client.
loadSettingsPage(). loadSettingsPage().
@@ -89,7 +91,7 @@ describe('browser/settings.html', function desc() {
}); });
describe('Server list', () => { describe('Server list', () => {
it('should open the corresponding tab when a server list item is clicked', async () => { it.skip('should open the corresponding tab when a server list item is clicked', async () => {
env.addClientCommands(this.app.client); env.addClientCommands(this.app.client);
await this.app.client. await this.app.client.
loadSettingsPage(). loadSettingsPage().
@@ -339,13 +341,9 @@ describe('browser/settings.html', function desc() {
it('should remove existing team on click Remove', async () => { it('should remove existing team on click Remove', async () => {
await this.app.client. await this.app.client.
element('.modal-dialog').click('.btn=Remove'). element('.modal-dialog').click('.btn=Remove').
pause(500); waitForExist(modalTitleSelector, 5000, true);
const existing = await this.app.client.isExisting(modalTitleSelector);
existing.should.be.false;
await this.app.client. await this.app.client.waitForVisible('#serversSaveIndicator', 10000, true);
click('#btnClose').
pause(500);
const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
savedConfig.teams.should.deep.equal(config.teams.slice(1)); savedConfig.teams.should.deep.equal(config.teams.slice(1));
@@ -354,13 +352,9 @@ describe('browser/settings.html', function desc() {
it('should NOT remove existing team on click Cancel', async () => { it('should NOT remove existing team on click Cancel', async () => {
await this.app.client. await this.app.client.
element('.modal-dialog').click('.btn=Cancel'). element('.modal-dialog').click('.btn=Cancel').
pause(500); waitForExist(modalTitleSelector, 5000, true);
const existing = await this.app.client.isExisting(modalTitleSelector);
existing.should.be.false;
await this.app.client. await this.app.client.waitForVisible('#serversSaveIndicator', 10000, true);
click('#btnClose').
pause(500);
const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
savedConfig.teams.should.deep.equal(config.teams); savedConfig.teams.should.deep.equal(config.teams);

View File

@@ -16,7 +16,7 @@ describe('PermissionManager', function() {
}); });
}); });
it('should grant a permisson for an origin', function() { it('should grant a permission for an origin', function() {
const ORIGIN = 'origin'; const ORIGIN = 'origin';
const PERMISSION = 'permission'; const PERMISSION = 'permission';
const manager = new PermissionManager(permissionFile); const manager = new PermissionManager(permissionFile);
@@ -33,7 +33,7 @@ describe('PermissionManager', function() {
manager.isGranted(ORIGIN, PERMISSION + '_another').should.be.false; manager.isGranted(ORIGIN, PERMISSION + '_another').should.be.false;
}); });
it('should deny a permisson for an origin', function() { it('should deny a permission for an origin', function() {
const ORIGIN = 'origin'; const ORIGIN = 'origin';
const PERMISSION = 'permission'; const PERMISSION = 'permission';
const manager = new PermissionManager(permissionFile); const manager = new PermissionManager(permissionFile);
@@ -50,7 +50,7 @@ describe('PermissionManager', function() {
manager.isDenied(ORIGIN, PERMISSION + '_another').should.be.false; manager.isDenied(ORIGIN, PERMISSION + '_another').should.be.false;
}); });
it('should save permissons to the file', function() { it('should save permissions to the file', function() {
const ORIGIN = 'origin'; const ORIGIN = 'origin';
const PERMISSION = 'permission'; const PERMISSION = 'permission';
const manager = new PermissionManager(permissionFile); const manager = new PermissionManager(permissionFile);

6544
yarn.lock

File diff suppressed because it is too large Load Diff