Compare commits

...

80 Commits

Author SHA1 Message Date
akashnimare
292e1b4d15 test: set default language for spellchecker 2017-12-15 19:21:07 +05:30
akashnimare
64a12dca09 test: run all the tests on appveyor. 2017-12-14 00:26:07 +05:30
akashnimare
d1d19327ba travis: rename tests. 2017-12-14 00:03:46 +05:30
Akash Nimare
dc6a1c3c0b travis: only run e2e & linting test on Linux 2017-12-13 23:46:57 +05:30
simplyahmazing
63005d20ca combine test cmds into one cmd 2017-12-13 10:10:02 -05:00
simplyahmazing
600e8acdfa Merge branch 'master' into setup-karma-for-unit-tests 2017-12-13 09:54:05 -05:00
akashnimare
d7a0b63d62 test: fix failing e2e test on travis 2017-12-13 20:05:07 +05:30
akashnimare
a193ecf229 design: update new server page #340. 2017-12-13 18:54:31 +05:30
simplyahmazing
3f01774d0a fix app starts e2e test 2017-12-11 16:42:09 -05:00
simplyahmazing
808dffd2ed merge upstream master 2017-12-11 16:37:32 -05:00
simplyahmazing
6b51f6d9a6 enable spellchecker via config for test 2017-12-11 16:34:23 -05:00
simplyahmazing
36342145da remove flag to force enable spellchecker 2017-12-11 16:20:52 -05:00
akashnimare
31f04754a4 design: fixed positioning of create-new-org link 2017-12-11 16:08:23 +05:30
akashnimare
ae7374475f design: Update UI for server section #340 2017-12-11 15:42:50 +05:30
akashnimare
7697d5d698 electron: update electron to v1.7.9 #213 2017-12-11 15:09:56 +05:30
simplyahmazing
7b639129b3 merge upstream master 2017-12-06 11:53:50 -05:00
simplyahmazing
89ae4585e6 rename test file 2017-12-06 11:45:02 -05:00
simplyahmazing
469b827425 remove unused dep section from package.json 2017-12-06 11:43:52 -05:00
simplyahmazing
7feb0e4280 remove karma-coverage 2017-12-06 11:33:58 -05:00
akashnimare
d3e1b5de45 update app configs 2017-12-06 19:46:24 +05:30
Akash Nimare
9efa6191f7 Merge pull request #349 from zulip/improve-debian-installer
linux: Improve debian installer
2017-12-06 18:17:57 +05:30
simplyahmazing
8cd8bac6a7 remove browserify dep 2017-12-06 06:51:30 -05:00
simplyahmazing
ce1e902e89 run unit tests on travis/appveyor 2017-12-05 13:34:25 -05:00
akashnimare
d86797d2fc debian: replace bash shebang with '#!/usr/bin/env bash" for portability.
According to the debian config rules '#!/usr/bin/env bash' violates
the quality standard which isn't allowed.

More info - https://github.com/Microsoft/vscode/issues/35638
2017-12-05 23:58:26 +05:30
simplyahmazing
3baa2c6ca5 setup spellchecker test 2017-12-05 13:27:07 -05:00
simplyahmazing
2114ccfb40 setup karma for running renderer process tests 2017-12-05 13:25:51 -05:00
akashnimare
23eef7edb0 debian: remove app settings on uninstall 2017-12-05 22:15:18 +05:30
akashnimare
a1d5a35ccf debian: Remove config files when user uninstalls app 2017-12-05 21:01:26 +05:30
akashnimare
62e8dfe180 Rename afterRemove script to debian uninstaller 2017-12-05 20:54:39 +05:30
Akash Nimare
8322054984 Merge pull request #347 from cPhost/deb
debian-installer: add apt repo for debian
2017-12-05 18:42:15 +05:30
Akash Nimare
13ae6f07e9 Add comment for adding apt repo 2017-12-05 18:41:06 +05:30
cPhost
dab92be54c debian installer: remove the apt repo after unistallation 2017-12-05 07:29:45 -05:00
cPhost
fe9c66d8c2 debian-installer: add apt repo for debian 2017-12-05 07:29:34 -05:00
akashnimare
43b4d511dc init default settings properly fixes #348 2017-12-04 17:19:25 +05:30
akashnimare
aa5a47ad53 Make app window thinner fixes #332 2017-12-04 15:19:43 +05:30
Akash Nimare
ce27f92900 Merge pull request #346 from cPhost/about-page
about-page: add links for zulip-electron and license.
2017-12-04 14:54:13 +05:30
cPhost
7be051bb6e about-page: center everything, add links for zulip-electron, license 2017-12-03 18:02:34 -05:00
Akash Nimare
c2a01adabe Merge pull request #345 from cPhost/logger
logger: add console helper to log for both file and console
2017-12-04 01:13:07 +05:30
cPhost
770926e6eb logger: add console helper to log for both file and console 2017-12-02 11:58:28 -05:00
Akash Nimare
10ef627f59 Add notifications troubleshooting 2017-12-01 20:43:52 +05:30
simplyahmazing
c6f1f99fe9 move integration tests into e2e dir 2017-11-30 20:47:25 -05:00
akashnimare
4adba0f4b4 Update electron-builder to v19.46.4 2017-11-24 17:00:03 +05:30
akashnimare
ed590c26e3 Added whitelist zulip server 2017-11-23 22:38:28 +05:30
akashnimare
6d10291a87 🎉 v1.7.0 2017-11-22 20:10:59 +05:30
akashnimare
3fe3a3da85 Update electron to v1.6.15 2017-11-22 16:21:39 +05:30
akashnimare
ba64438a99 Improve Add Server page for new users [WIP] #340 2017-11-22 14:39:39 +05:30
Akash Nimare
bcc27894c4 Merge pull request #337 from SimplyAhmazing/setup-e2e-tests
setup e2e tests
2017-11-22 13:28:31 +05:30
Akash Nimare
0dd0f593d1 Merge pull request #338 from sroy8091/issue_#336
Better error message on invalid server fixes #336
2017-11-21 21:08:08 +05:30
Sumit Roy
f5e9342f78 fail to connect message #336 2017-11-21 11:31:42 +05:30
simplyahmazing
083ccdf229 remove unused imports 2017-11-20 11:14:22 -05:00
simplyahmazing
1261786db2 remove unused dependencies 2017-11-20 11:06:05 -05:00
simplyahmazing
7f567f55c3 setup e2e tests 2017-11-19 16:48:21 -05:00
akashnimare
dcd2abca6e v1.6.0-beta 2017-11-16 00:32:32 +05:30
Akash Nimare
2fb9efb981 Merge pull request #335 from zulip/electron-shortcut-fix
Remove electron-localshortcut completely
2017-11-15 16:56:42 +05:30
akashnimare
7245b6a110 Move electron-debug to devDependencies 2017-11-15 04:59:59 +05:30
akashnimare
bcb8ffb55f Remove electron-LocalShortcut completely
This commit removes the usage of "electron-localshortcut" completely.
Now, we rely on only menu accelerators for shortcuts. It's risky to register a local shortcuts in the app window
either using electronLocalShortcut or globalShortcut as the registered shortcuts could interfare with
OS global shortcuts which is very frustrating. This fixes #317 once and for all.
2017-11-15 03:39:51 +05:30
akashnimare
77094596a5 Use electron-debug in development only WIP #317
electron-debug hijacks the CMD/CTRL+R and reloads the whole app,
whereas we only need to reload the current server. Removed those commands from
electronLocalShortcuts as well as they are already registered in menu items.
2017-11-15 03:07:36 +05:30
Akash Nimare
06ad44bdd7 Merge pull request #333 from zulip/appimage-autoupdates
Add AppImage autoupdates fixes #333
2017-11-11 20:12:24 +05:30
akashnimare
e719ba139c Update electron-builder to latest version 2017-11-11 20:10:53 +05:30
akashnimare
9853e9226c Better tray icon for retina display, fixes #330 2017-11-08 12:26:52 +05:30
akashnimare
f2c76b5ca3 Enable auto-update on Linux (AppImage) 2017-11-04 01:31:45 +05:30
Akash Nimare
e6dbff995b Merge pull request #327 from zulip/taskbar-setting-option
Setting option for Windows taskbar flash fixes #299
2017-11-03 00:09:58 +05:30
akashnimare
4578d4a5f7 typo in setting 2017-11-03 00:06:34 +05:30
akashnimare
4b895a2312 Don't show flash taskbar setting on Linux/macOS 2017-11-02 23:54:38 +05:30
akashnimare
53c0428a3a Add setting to control Windows taskbar flashing #299 2017-11-02 20:58:35 +05:30
akashnimare
0a1866abb5 Show Detailed error message on invaild Zulip server #325 2017-11-01 17:59:00 +05:30
Akash Nimare
ce862a4890 Merge pull request #326 from zulip/remove-python-version-file
Remove python version file

Fixes failing tests on Travis Linux
2017-10-31 20:55:17 +05:30
simplyahmazing
1b1ad2cd61 remove .python-version file from repo 2017-10-28 20:06:56 -04:00
simplyahmazing
ead7a06308 ignore .python-version files 2017-10-28 20:06:26 -04:00
akashnimare
6659dd5097 Update electron-builder & updater to latest 2017-10-26 11:54:55 +05:30
akashnimare
ed1f0f6d5b Update electron-builder & updater to latest 2017-10-24 18:38:00 +05:30
akashnimare
79acf8a6e1 Add option to remove app settings
Menu item "Reset app settings" now remove all the configurations/settings files related to app.
Previously it used to remove only window-state.json. This helps a bit in #310.
2017-10-24 18:29:35 +05:30
akashnimare
8e0033f03e Handle certificate issuer error
Fixes, #316
2017-10-21 01:47:16 +05:30
Akash Nimare
9144c2630d Merge pull request #322 from zulip/spellchecker-osx-fix
Spellchecker Improvements
2017-10-20 23:52:24 +05:30
akashnimare
fae05fc3b1 Initialize default app settings
Settings are initialized only when user clicks on General/Server/Network section settings
In case, user doesn't visit these section, those values set to be null automatically.
This fix makes sure the default settings are correctly set to either true or false.
2017-10-18 21:38:48 +05:30
akashnimare
73603a4fd2 Add settings to disable/enable spellchecker 2017-10-18 21:36:01 +05:30
akashnimare
a498ffc7d6 Update spellchecker to v1.1.2 2017-10-18 04:17:51 +05:30
akashnimare
7afcf13401 Re-write and improve spellchecker class
Rewrote the Spellchecker class so that we can have better control
over the context menu and spellchecker.
2017-10-18 04:14:02 +05:30
akashnimare
89a292559d Set English as default language for spellchecker on Linux/Windows 2017-10-17 21:57:51 +05:30
akashnimare
be14517caf Set server language for spellchecker on macOS
Ideally spellchecker should detect the language, but on macOS, it fails to auto-detect the lanugage user is typing in
that's why we need to mention it explicitly. We set this language with the help of the default language of the server.
2017-10-17 00:29:50 +05:30
44 changed files with 9157 additions and 336 deletions

8
.gitignore vendored
View File

@@ -23,4 +23,10 @@ yarn-error.log*
# miscellaneous
.idea
config.gypi
config.gypi
# Test generated files
tests/e2e/package.json
coverage
.python-version

View File

@@ -1 +0,0 @@
2.7.9

View File

@@ -18,8 +18,9 @@ node_js:
- '6'
before_install:
- npm install -g gulp
- npm install
- ./scripts/travis-xvfb.sh
- npm install -g gulp
- npm install
cache:
directories:
@@ -33,4 +34,4 @@ notifications:
urls:
- https://zulip.org/zulipbot/travis
on_success: always
on_failure: always
on_failure: always

View File

@@ -7,9 +7,8 @@ const isDev = require('electron-is-dev');
const ConfigUtil = require('./../renderer/js/utils/config-util.js');
function appUpdater() {
// Don't initiate auto-updates in development and on Linux system
// since autoUpdater doesn't work on Linux
if (isDev || process.platform === 'linux') {
// Don't initiate auto-updates in development
if (isDev) {
return;
}

View File

@@ -1,8 +1,8 @@
'use strict';
const path = require('path');
const electron = require('electron');
const electronLocalshortcut = require('electron-localshortcut');
const windowStateKeeper = require('electron-window-state');
const isDev = require('electron-is-dev');
const appMenu = require('./menu');
const { appUpdater } = require('./autoupdater');
const { crashHandler } = require('./crash-reporter');
@@ -14,7 +14,10 @@ const { app, ipcMain } = electron;
const BadgeSettings = require('./../renderer/js/pages/preference/badge-settings.js');
// Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
// in development mode
if (isDev) {
require('electron-debug')();
}
// Prevent window being garbage collected
let mainWindow;
@@ -63,8 +66,8 @@ function createMainWindow() {
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
minWidth: 600,
minHeight: 500,
minWidth: 300,
minHeight: 400,
webPreferences: {
plugins: true,
allowDisplayingInsecureContent: true,
@@ -94,9 +97,6 @@ function createMainWindow() {
win.hide();
}
}
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
});
win.setTitle('Zulip');
@@ -124,33 +124,12 @@ function createMainWindow() {
return win;
}
function registerLocalShortcuts(page) {
// Somehow, reload action cannot be overwritten by the menu item
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
page.send('reload-current-viewer');
});
// Also adding these shortcuts because some users might want to use it instead of CMD/Left-Right
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
page.send('back');
});
electronLocalshortcut.register(mainWindow, 'CommandOrControl+]', () => {
page.send('forward');
});
}
// eslint-disable-next-line max-params
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
event.preventDefault();
callback(true);
});
app.on('window-all-closed', () => {
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
});
app.on('activate', () => {
if (!mainWindow) {
mainWindow = createMainWindow();
@@ -165,8 +144,6 @@ app.on('ready', () => {
const page = mainWindow.webContents;
registerLocalShortcuts(page);
page.on('dom-ready', () => {
mainWindow.show();
});
@@ -232,18 +209,8 @@ app.on('ready', () => {
});
ipcMain.on('register-server-tab-shortcut', (event, index) => {
electronLocalshortcut.register(mainWindow, `CommandOrControl+${index}`, () => {
// Array index == Shown index - 1
page.send('switch-server-tab', index - 1);
});
});
ipcMain.on('local-shortcuts', (event, enable) => {
if (enable) {
registerLocalShortcuts(page);
} else {
electronLocalshortcut.unregisterAll(mainWindow);
}
// Array index == Shown index - 1
page.send('switch-server-tab', index - 1);
});
ipcMain.on('toggleAutoLauncher', (event, AutoLaunchValue) => {
@@ -251,11 +218,6 @@ app.on('ready', () => {
});
});
app.on('will-quit', () => {
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
});
app.on('before-quit', () => {
isQuitting = true;
});

View File

@@ -370,10 +370,20 @@ class AppMenu {
}
static resetAppSettings() {
const getAppPath = path.join(app.getPath('appData'), appName, 'window-state.json');
// We save App's settings/configurations in following files
const settingFiles = ['window-state.json', 'domain.json', 'settings.json'];
fs.unlink(getAppPath, () => {
setTimeout(() => AppMenu.sendAction('clear-app-data'), 1000);
settingFiles.forEach(settingFileName => {
const getSettingFilesPath = path.join(app.getPath('appData'), appName, settingFileName);
fs.access(getSettingFilesPath, error => {
if (error) {
console.log(error);
} else {
fs.unlink(getSettingFilesPath, () => {
AppMenu.sendAction('clear-app-data');
});
}
});
});
}

904
app/package-lock.json generated Normal file
View File

@@ -0,0 +1,904 @@
{
"name": "zulip",
"version": "1.7.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@paulcbetts/cld": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/@paulcbetts/cld/-/cld-2.4.6.tgz",
"integrity": "sha1-qZL2vEPKshKsLESIpnHPMC+LYuc=",
"requires": {
"glob": "5.0.15",
"nan": "2.8.0",
"rimraf": "2.6.2",
"underscore": "1.8.3"
}
},
"@paulcbetts/spellchecker": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@paulcbetts/spellchecker/-/spellchecker-4.0.6.tgz",
"integrity": "sha512-9lhLEvWfAB00n2oOM/S08sna9AuFk+b+bPk8ficpSa2X0Ll40PahMwfFS3G54nqQBIFFZgTPrhoHtCLAao0xmg==",
"requires": {
"nan": "2.8.0"
}
},
"ajv": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"requires": {
"co": "4.6.0",
"json-stable-stringify": "1.0.1"
}
},
"applescript": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz",
"integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc="
},
"argparse": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
"integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
"requires": {
"sprintf-js": "1.0.3"
}
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert-plus": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"auto-launch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/auto-launch/-/auto-launch-5.0.1.tgz",
"integrity": "sha1-IBWoowOEq+Dn+Yy9yoFFzxVHU64=",
"requires": {
"applescript": "1.0.0",
"mkdirp": "0.5.1",
"path-is-absolute": "1.0.1",
"untildify": "3.0.2",
"winreg": "1.2.2"
}
},
"aws-sign2": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bcp47": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz",
"integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4="
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
}
},
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
"bluebird-lst": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.5.tgz",
"integrity": "sha512-Ey0bDNys5qpYPhZ/oQ9vOEvD0TYQDTILMXWP2iGfvMg7rSDde+oV4aQQgqRH+CvBFNz2BSDQnPGMUl6LKBUUQA==",
"requires": {
"bluebird": "3.5.1"
}
},
"boom": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"requires": {
"hoek": "2.16.3"
}
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"builder-util-runtime": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-3.2.0.tgz",
"integrity": "sha512-VRvyyLiZZSBjcUTqEsHlBJSK0s6uVQChO7kbmVeU6QmSJ7TtsotNQELO6lbahwZMAQ4Z/haCKhlLBDdhW+3aqA==",
"requires": {
"bluebird-lst": "1.0.5",
"debug": "3.1.0",
"fs-extra-p": "4.4.4",
"sax": "1.2.4"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"requires": {
"delayed-stream": "1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cryptiles": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
"requires": {
"boom": "2.10.1"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"optional": true,
"requires": {
"jsbn": "0.1.1"
}
},
"electron-is-dev": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-0.3.0.tgz",
"integrity": "sha1-FOb9pcaOnk7L7/nM8DfL18BcWv4="
},
"electron-log": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.7.tgz",
"integrity": "sha512-pRfRn53MQGJ9L1+aC0VFcps0Uo5NM4RYsdvIdnjiV6J+krMr4cgBZ/DDA3kjNsr0D0kzo2WKpMgn2fAVra99rg=="
},
"electron-remote": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/electron-remote/-/electron-remote-1.2.0.tgz",
"integrity": "sha512-Fo2wnwK2tzd81Ux4pfNhz9DwHBoooZahdWBqOh9HtESYh2jrcsjc6FAibIu2oIOk71T1USyC7OBcqE8BZw3FGQ==",
"requires": {
"debug": "2.6.9",
"hashids": "1.1.4",
"lodash.get": "4.4.2",
"pify": "2.3.0",
"rxjs": "5.5.2",
"xmlhttprequest": "1.8.0"
}
},
"electron-spellchecker": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/electron-spellchecker/-/electron-spellchecker-1.1.2.tgz",
"integrity": "sha512-AdzD/Q82Svk9EDTc65vRr271UPLVIxsruKJM0iwqxEG9Y/CogNhEAJz/asV0BFWom4tpdB6cHcLbYePb11Musw==",
"requires": {
"@paulcbetts/cld": "2.4.6",
"@paulcbetts/spellchecker": "4.0.6",
"bcp47": "1.1.2",
"debug": "2.6.9",
"electron-remote": "1.2.0",
"keyboard-layout": "2.0.13",
"lru-cache": "4.1.1",
"mkdirp": "0.5.1",
"pify": "2.3.0",
"rxjs": "5.5.2",
"rxjs-serial-subscription": "0.1.1",
"spawn-rx": "2.0.12"
}
},
"electron-updater": {
"version": "2.16.2",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-2.16.2.tgz",
"integrity": "sha512-gv1kezjdXR6sw266aTzfs7HgPO5vaf5TsBFh7kMi47JABAIJSO3n+U79pSBperPVtGdqWQ4WfM6+2irrFvYXLw==",
"requires": {
"bluebird-lst": "1.0.5",
"builder-util-runtime": "3.2.0",
"electron-is-dev": "0.3.0",
"fs-extra-p": "4.4.4",
"js-yaml": "3.10.0",
"lazy-val": "1.0.2",
"lodash.isequal": "4.5.0",
"semver": "5.4.1",
"source-map-support": "0.5.0"
}
},
"electron-window-state": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-4.1.1.tgz",
"integrity": "sha1-azT9wxs4UU3+yLfI97XUrdtnYy0=",
"requires": {
"deep-equal": "1.0.1",
"jsonfile": "2.4.0",
"mkdirp": "0.5.1"
},
"dependencies": {
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"requires": {
"graceful-fs": "4.1.11"
}
}
}
},
"esprima": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
},
"event-kit": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.4.0.tgz",
"integrity": "sha512-ZXd9jxUoc/f/zdLdR3OUcCzT84WnpaNWefquLyE125akIC90sDs8S3T/qihliuVsaj7Osc0z8lLL2fjooE9Z4A=="
},
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.5",
"mime-types": "2.1.17"
}
},
"fs-extra": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
"integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=",
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "4.0.0",
"universalify": "0.1.1"
}
},
"fs-extra-p": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-4.4.4.tgz",
"integrity": "sha512-zHsMNJWhXD184QfHKEIFSQSgAFNV7v9J+Nt2XpaLZp2nTz6WxZNV+R4G2uYeGeLTMaKvUZiqGKrH/4iFCupcUA==",
"requires": {
"bluebird-lst": "1.0.5",
"fs-extra": "4.0.2"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}
}
},
"glob": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
"requires": {
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"har-schema": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
"integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4="
},
"har-validator": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
"requires": {
"ajv": "4.11.8",
"har-schema": "1.0.5"
}
},
"hashids": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/hashids/-/hashids-1.1.4.tgz",
"integrity": "sha512-U/fnTE3edW0AV92ZI/BfEluMZuVcu3MDOopsN7jS+HqDYcarQo8rXQiWlsBlm0uX48/taYSdxRsfzh2HRg5Z6w=="
},
"hawk": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
"requires": {
"boom": "2.10.1",
"cryptiles": "2.0.5",
"hoek": "2.16.3",
"sntp": "1.0.9"
}
},
"hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
},
"http-signature": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
"requires": {
"assert-plus": "0.2.0",
"jsprim": "1.4.1",
"sshpk": "1.13.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-yaml": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
"integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
"requires": {
"argparse": "1.0.9",
"esprima": "4.0.0"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"requires": {
"jsonify": "0.0.0"
}
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "4.1.11"
}
},
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}
}
},
"keyboard-layout": {
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/keyboard-layout/-/keyboard-layout-2.0.13.tgz",
"integrity": "sha512-WxVc3bBITttHozSyEYPsyr5rN2KQuXtEaXMlQfQjEze1JrkLw30yH/bcNn1IGx48b+tdOdybpnq++JFLU2FaZg==",
"requires": {
"event-kit": "2.4.0",
"nan": "2.8.0"
}
},
"lazy-val": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.2.tgz",
"integrity": "sha512-2BaSu6qVnicKdWQPysrffZVFAKcPcZQ/q2YyeSjAxWaJlvCvKSrkcvsSHlleeIfA//fW2goTcYDTy2cBLN7+PQ=="
},
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
},
"lru-cache": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
"requires": {
"pseudomap": "1.0.2",
"yallist": "2.1.2"
}
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"requires": {
"mime-db": "1.30.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.8"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
"integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo="
},
"node-json-db": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/node-json-db/-/node-json-db-0.7.3.tgz",
"integrity": "sha1-v2Mf9NTPQhHL3/5srmqq/m7lTN8=",
"requires": {
"mkdirp": "0.5.1"
}
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"performance-now": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
"integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"qs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
},
"request": {
"version": "2.81.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
"requires": {
"aws-sign2": "0.6.0",
"aws4": "1.6.0",
"caseless": "0.12.0",
"combined-stream": "1.0.5",
"extend": "3.0.1",
"forever-agent": "0.6.1",
"form-data": "2.1.4",
"har-validator": "4.2.1",
"hawk": "3.1.3",
"http-signature": "1.1.1",
"is-typedarray": "1.0.0",
"isstream": "0.1.2",
"json-stringify-safe": "5.0.1",
"mime-types": "2.1.17",
"oauth-sign": "0.8.2",
"performance-now": "0.2.0",
"qs": "6.4.0",
"safe-buffer": "5.1.1",
"stringstream": "0.0.5",
"tough-cookie": "2.3.3",
"tunnel-agent": "0.6.0",
"uuid": "3.1.0"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"requires": {
"glob": "7.1.2"
},
"dependencies": {
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
}
}
},
"rxjs": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz",
"integrity": "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==",
"requires": {
"symbol-observable": "1.1.0"
}
},
"rxjs-serial-subscription": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/rxjs-serial-subscription/-/rxjs-serial-subscription-0.1.1.tgz",
"integrity": "sha1-pCsdsL8QlLCSMRkeJ3jKP8+e0Uc=",
"requires": {
"rxjs": "5.5.2"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
},
"sntp": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
"requires": {
"hoek": "2.16.3"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.0.tgz",
"integrity": "sha512-vUoN3I7fHQe0R/SJLKRdKYuEdRGogsviXFkHHo17AWaTGv17VLnxw+CFXvqy+y4ORZ3doWLQcxRYfwKrsd/H7Q==",
"requires": {
"source-map": "0.6.1"
}
},
"spawn-rx": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz",
"integrity": "sha512-gOPXiQQFQ9lTOLuys0iMn3jfxxv9c7zzwhbYLOEbQGvEShHVJ5sSR1oD3Daj88os7jKArDYT7rbOKdvNhe7iEg==",
"requires": {
"debug": "2.6.9",
"lodash.assign": "4.2.0",
"rxjs": "5.5.2"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"sshpk": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"requires": {
"asn1": "0.2.3",
"assert-plus": "1.0.0",
"bcrypt-pbkdf": "1.0.1",
"dashdash": "1.14.1",
"ecc-jsbn": "0.1.1",
"getpass": "0.1.7",
"jsbn": "0.1.1",
"tweetnacl": "0.14.5"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}
}
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
},
"symbol-observable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz",
"integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw=="
},
"tough-cookie": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"requires": {
"punycode": "1.4.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "5.1.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"universalify": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
},
"untildify": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz",
"integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E="
},
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "1.3.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}
}
},
"winreg": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.2.tgz",
"integrity": "sha1-hQmvo7ccW70RCm18YkfsZ3NsWY8="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"wurl": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/wurl/-/wurl-2.5.0.tgz",
"integrity": "sha1-g7qrSEi5hmnSFISg/NmjSrpXKOk="
},
"xmlhttprequest": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
"integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
}

View File

@@ -1,14 +1,13 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "1.5.0",
"version": "1.7.0",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"email": "<svnitakash@gmail.com>",
"copyright": "©2017 Kandra Labs, Inc.",
"copyright": "Kandra Labs, Inc.",
"author": {
"name": "Kandra Labs, Inc.",
"email": "svnitakash@gmail.com"
"email": "support@zulipchat.com"
},
"repository": {
"type": "git",
@@ -27,16 +26,14 @@
"InstantMessaging"
],
"dependencies": {
"electron-debug": "1.4.0",
"auto-launch": "5.0.1",
"electron-is-dev": "0.3.0",
"electron-localshortcut": "2.0.2",
"electron-log": "2.2.7",
"electron-spellchecker": "1.2.0",
"electron-updater": "2.8.9",
"electron-spellchecker": "1.1.2",
"electron-window-state": "4.1.1",
"electron-updater": "2.16.2",
"node-json-db": "0.7.3",
"request": "2.81.0",
"wurl": "2.5.0",
"electron-window-state": "4.1.1",
"auto-launch": "5.0.1"
"wurl": "2.5.0"
}
}

View File

@@ -7,25 +7,37 @@
<body>
<div class="about">
<img class="logo" src="../resources/zulip.png" />
<p class="detail" id="version">version ?.?.?</p>
<p class="detail" id="version">v?.?.?</p>
<div class="maintenance-info">
<p class="detail maintainer">Maintained by Zulip</p>
<p class="detail license">Available under the Apache License</p>
<a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a>
<p class="detail maintainer">
Maintained by <a onclick="linkInBrowser('website')">Zulip</a>
</p>
<p class="detail license">
Available under the <a onclick="linkInBrowser('license')">Apache 2.0 License</a>
</p>
<a class="bug" onclick="linkInBrowser('bug')" href="#">Found bug?</a>
</div>
</div>
<script>
const app = require('electron').remote.app;
const version_tag = document.getElementById('version');
version_tag.innerHTML = 'version ' + app.getVersion();
function linkInBrowser(event) {
const shell = require('electron').shell;
const url = "https://github.com/zulip/zulip-electron/issues/new?body=Please describe your issue and steps to reproduce it."
const { app } = require('electron').remote;
const { shell } = require('electron');
const version_tag = document.querySelector('#version');
version_tag.innerHTML = 'v' + app.getVersion();
function linkInBrowser(type) {
let url;
switch (type) {
case 'website':
url = "https://zulipchat.com";
break;
case 'license':
url = "https://github.com/zulip/zulip-electron/blob/master/LICENSE";
break;
default:
url = 'https://github.com/zulip/zulip-electron/issues/new?body=' +
'%3C!--Please%20describe%20your%20issue%20and%20steps%20to%20reproduce%20it.--%3E';
}
shell.openExternal(url);
}
</script>

View File

@@ -1,21 +1,23 @@
body {
background: #fafafa;
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-webkit-font-smoothing: subpixel-antialiased;
}
.logo {
display: block;
margin: 0 auto;
margin: -40px auto;
}
#version {
color: #aaa;
font-size: 0.9em;
color: #444343;
font-size: 1.3em;
padding-top: 40px;
}
.about {
margin-top: 50px;
margin: 25vh auto;
height: 25vh;
text-align: center;
}
@@ -42,9 +44,9 @@ body {
}
.maintenance-info {
cursor: pointer;
position: absolute;
width: 100%;
bottom: 20px;
left: 0px;
color: #444;
}
@@ -52,7 +54,6 @@ body {
.maintenance-info p {
margin: 0;
font-size: 1em;
width: 100%;
}
@@ -71,3 +72,11 @@ body {
.maintenance-info .bug:hover {
background-color: #32a692;
}
p.detail a {
color: #355f4c;
}
p.detail a:hover {
text-decoration: underline;
}

View File

@@ -5,7 +5,7 @@ body {
cursor: default;
user-select: none;
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
font-size: 14px;
color: #333;
background: #efefef;
@@ -24,60 +24,65 @@ kbd {
white-space: nowrap;
}
table, th, td {
table,
th,
td {
border-collapse: collapse;
color: #383430;
}
table {
table {
width: 100%;
margin-top: 18px;
margin-bottom: 18px;
}
}
table tr:nth-child(even) { background-color: #f7eee6; }
table tr:nth-child(even) {
background-color: #f7eee6;
}
table tr:nth-child(odd) { background-color: #fff8ef; }
table tr:nth-child(odd) {
background-color: #fff8ef;
}
td { padding: 5px; }
td {
padding: 5px;
}
td:nth-child(odd) {
text-align: right;
width: 50%;
text-align: right;
width: 50%;
}
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(../fonts/MaterialIcons-Regular.ttf) format('truetype');
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'), local('MaterialIcons-Regular'), url(../fonts/MaterialIcons-Regular.ttf) format('truetype');
}
@font-face {
font-family: 'Montserrat';
src: url(../fonts/Montserrat-Regular.ttf) format('truetype');
font-family: 'Montserrat';
src: url(../fonts/Montserrat-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
/* Preferred icon size */
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
/* Preferred icon size */
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
}
#content {
@@ -140,9 +145,15 @@ td:nth-child(odd) {
.title {
padding: 4px 0 6px 0;
font-weight: bold;
font-weight: 500;
color: #222c31;
text-transform: uppercase;
}
.page-title {
color: #222c31;
font-size: 15px;
font-weight: bold;
padding: 4px 0 6px 0;
}
.sub-title {
@@ -189,16 +200,18 @@ img.server-info-icon {
.setting-input-value {
flex-grow: 1;
font-size: 14px;
height: 24px;
border: none;
border-bottom: #ededed 1px solid;
height: 22px;
border-radius: 3px;
padding: 7px;
border: #ededed 2px solid;
outline-width: 0;
background: transparent;
max-width: 500px;
}
.setting-input-value:focus {
border-bottom: #7cb980 1px solid;
border: #7cb980 2px solid;
border-radius: 3px;
}
.setting-block {
@@ -224,7 +237,7 @@ img.server-info-icon {
.action i {
margin-right: 5px;
font-size: 18px;
line-height: 27px;
line-height: 26px;
}
.settings-pane {
@@ -315,75 +328,83 @@ i.open-tab-button {
}
#server-info-container {
min-height: calc(100% - 235px);
min-height: calc(100% - 235px);
}
#create-organization-container {
font-size: 1.15em;
margin-bottom: 15px;
font-size: 1.15em;
position: fixed;
bottom: 15px;
}
#create-organization-container i {
position: relative;
top: 3px;
position: relative;
top: 3px;
}
#open-create-org-link {
color: #666;
cursor: pointer;
text-decoration: none;
color: #666;
cursor: pointer;
text-decoration: none;
}
#open-create-org-link:hover {
color: #005580;;
text-decoration: underline;
color: #005580;
;
text-decoration: underline;
}
.toggle {
position: absolute;
margin-left: -9999px;
visibility: hidden;
}
.toggle + label {
display: block;
position: relative;
cursor: pointer;
outline: none;
user-select: none;
position: absolute;
margin-left: -9999px;
visibility: hidden;
}
input.toggle-round + label {
padding: 2px;
width: 50px;
height: 25px;
background-color: #dddddd;
border-radius: 25px;
.toggle+label {
display: block;
position: relative;
cursor: pointer;
outline: none;
user-select: none;
}
input.toggle-round + label:before,
input.toggle-round + label:after {
display: block;
position: absolute;
top: 2px;
left: 2px;
bottom: 2px;
content: "";
input.toggle-round+label {
padding: 2px;
width: 50px;
height: 25px;
background-color: #dddddd;
border-radius: 25px;
}
input.toggle-round + label:before {
right: 2px;
background-color: #f1f1f1;
border-radius: 25px;
transition: background 0.4s;
input.toggle-round+label:before,
input.toggle-round+label:after {
display: block;
position: absolute;
top: 2px;
left: 2px;
bottom: 2px;
content: "";
}
input.toggle-round + label:after {
width: 25px;
height: 25px;
background-color: #fff;
border-radius: 100%;
transition: margin 0.4s;
input.toggle-round+label:before {
right: 2px;
background-color: #f1f1f1;
border-radius: 25px;
transition: background 0.4s;
}
input.toggle-round:checked + label:before {
background-color: #4EBFAC;
input.toggle-round+label:after {
width: 25px;
height: 25px;
background-color: #fff;
border-radius: 100%;
transition: margin 0.4s;
}
input.toggle-round:checked + label:after {
margin-left: 25px;
input.toggle-round:checked+label:before {
background-color: #4EBFAC;
}
input.toggle-round:checked+label:after {
margin-left: 25px;
}

View File

@@ -0,0 +1,69 @@
const NodeConsole = require('console').Console;
const fs = require('fs');
const { app } = require('electron').remote;
const isDev = require('electron-is-dev');
const browserConsole = console;
const logDir = `${app.getPath('userData')}/Logs`;
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
function customConsole(opts, type, ...args) {
const { nodeConsole, timestamp } = opts;
if (timestamp) {
args.unshift(timestamp());
}
if (!isDev) {
const nodeConsoleLog = nodeConsole[type] || nodeConsole.log;
nodeConsoleLog.apply(null, args);
}
browserConsole[type].apply(null, args);
}
function getTimestamp() {
const date = new Date();
const timestamp =
`${date.getMonth()}/${date.getDate()} ` +
`${date.getMinutes()}:${date.getSeconds()}`;
return timestamp;
}
function setConsoleProto(type) {
Object.defineProperty(this, type, {
value(...args) {
const { timestamp, nodeConsole } = this;
const opts = {
timestamp,
nodeConsole
};
customConsole.apply(null, [].concat(opts, type, args));
}
});
}
class Console {
constructor(opts = {}) {
let { timestamp, file } = opts;
file = `${logDir}/${file || 'console.log'}`;
if (timestamp === true) {
timestamp = getTimestamp;
}
const fileStream = fs.createWriteStream(file);
const nodeConsole = new NodeConsole(fileStream);
this.nodeConsole = nodeConsole;
this.timestamp = timestamp;
this.setUpConsole();
}
setUpConsole() {
for (const type in browserConsole) {
setConsoleProto.call(this, type);
}
}
}
module.exports = Console;

View File

@@ -43,6 +43,7 @@ class ServerManagerView {
this.initTabs();
this.initActions();
this.registerIpcs();
this.initDefaultSettings();
});
}
@@ -65,6 +66,31 @@ class ServerManagerView {
});
}
// Settings are initialized only when user clicks on General/Server/Network section settings
// In case, user doesn't visit these section, those values set to be null automatically
// This will make sure the default settings are correctly set to either true or false
initDefaultSettings() {
// Default settings which should be respected
const settingOptions = {
trayIcon: true,
useProxy: false,
showSidebar: true,
badgeOption: true,
startAtLogin: false,
enableSpellchecker: true,
showNotification: true,
betaUpdate: false,
silent: false,
lastActiveTab: 0
};
for (const i in settingOptions) {
if (ConfigUtil.getConfigItem(i) === null) {
ConfigUtil.setConfigItem(i, settingOptions[i]);
}
}
}
initSidebar() {
const showSidebar = ConfigUtil.getConfigItem('showSidebar', true);
this.toggleSidebar(showSidebar);
@@ -83,7 +109,6 @@ class ServerManagerView {
} else {
this.openSettings('Servers');
}
ipcRenderer.send('local-shortcuts', true);
}
initServer(server, index) {
@@ -257,9 +282,6 @@ class ServerManagerView {
// Clear DOM elements
this.$tabsContainer.innerHTML = '';
this.$webviewsContainer.innerHTML = '';
// Destroy shortcuts
ipcRenderer.send('local-shortcuts', false);
}
reloadView() {

View File

@@ -45,7 +45,7 @@ class BadgeSettings {
updateOverlayIcon(messageCount, mainWindow) {
if (!mainWindow.isFocused()) {
mainWindow.flashFrame(true);
mainWindow.flashFrame(ConfigUtil.getConfigItem('flashTaskbarOnMessage'));
}
if (messageCount === 0) {
mainWindow.setOverlayIcon(null, '');

View File

@@ -13,7 +13,7 @@ class CreateOrganziation extends BaseComponent {
return `
<div class="setting-row">
<div class="setting-description">
<span id="open-create-org-link">Create a new organization on zulipchat.com<i class="material-icons open-tab-button">open_in_new</i></span>
<span id="open-create-org-link">Or create a new organization on zulipchat.com<i class="material-icons open-tab-button">open_in_new</i></span>
</div>
<div class="setting-control"></div>
</div>

View File

@@ -29,9 +29,13 @@ class GeneralSection extends BaseSection {
<div class="setting-control"></div>
</div>
<div class="setting-row" id="badge-option">
<div class="setting-description">Show app unread badge</div>
<div class="setting-control"></div>
</div>
<div class="setting-description">Show app unread badge</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="flash-taskbar-option" style= "display:${process.platform === 'win32' ? '' : 'none'}">
<div class="setting-description">Flash taskbar on new message</div>
<div class="setting-control"></div>
</div>
</div>
<div class="title">Desktop Notification</div>
<div class="settings-card">
@@ -57,6 +61,10 @@ class GeneralSection extends BaseSection {
<div class="setting-description">Start app at login</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="enable-spellchecker-option">
<div class="setting-description">Enable Spellchecker (requires restart)</div>
<div class="setting-control"></div>
</div>
</div>
<div class="title">Reset Application Data</div>
<div class="settings-card">
@@ -74,12 +82,19 @@ class GeneralSection extends BaseSection {
this.props.$root.innerHTML = this.template();
this.updateTrayOption();
this.updateBadgeOption();
this.updateUpdateOption();
this.updateSilentOption();
this.updateUpdateOption();
this.updateSidebarOption();
this.updateStartAtLoginOption();
this.updateResetDataOption();
this.showDesktopNotification();
this.enableSpellchecker();
// Platform specific settings
// Flashing taskbar on Windows
if (process.platform === 'win32') {
this.updateFlashTaskbar();
}
}
updateTrayOption() {
@@ -108,6 +123,18 @@ class GeneralSection extends BaseSection {
});
}
updateFlashTaskbar() {
this.generateSettingOption({
$element: document.querySelector('#flash-taskbar-option .setting-control'),
value: ConfigUtil.getConfigItem('flashTaskbarOnMessage', true),
clickHandler: () => {
const newValue = !ConfigUtil.getConfigItem('flashTaskbarOnMessage');
ConfigUtil.setConfigItem('flashTaskbarOnMessage', newValue);
this.updateFlashTaskbar();
}
});
}
updateUpdateOption() {
this.generateSettingOption({
$element: document.querySelector('#betaupdate-option .setting-control'),
@@ -170,6 +197,18 @@ class GeneralSection extends BaseSection {
});
}
enableSpellchecker() {
this.generateSettingOption({
$element: document.querySelector('#enable-spellchecker-option .setting-control'),
value: ConfigUtil.getConfigItem('enableSpellchecker', true),
clickHandler: () => {
const newValue = !ConfigUtil.getConfigItem('enableSpellchecker');
ConfigUtil.setConfigItem('enableSpellchecker', newValue);
this.enableSpellchecker();
}
});
}
clearAppDataDialog() {
const clearAppDataMessage = 'By clicking proceed you will be removing all added accounts and preferences from Zulip. When the application restarts, it will be as if you are starting Zulip for the first time.';
const getAppPath = path.join(app.getPath('appData'), app.getName());

View File

@@ -13,12 +13,13 @@ class NewServerForm extends BaseComponent {
return `
<div class="settings-card">
<div class="server-info-right">
<div class="title">URL of your Zulip organization</div>
<div class="server-info-row">
<input class="setting-input-value" autofocus placeholder="Enter the URL of your Zulip organization..."/>
<input class="setting-input-value" autofocus placeholder="acme.zulipchat.com"/>
</div>
<div class="server-info-row">
<div class="action blue server-save-action">
<i class="material-icons">check_box</i>
<i class="material-icons">add_box</i>
<span>Add</span>
</div>
</div>

View File

@@ -1,7 +1,7 @@
'use strict';
const BaseComponent = require(__dirname + '/js/components/base.js');
const {ipcRenderer} = require('electron');
const { ipcRenderer } = require('electron');
const Nav = require(__dirname + '/js/pages/preference/nav.js');
const ServersSection = require(__dirname + '/js/pages/preference/servers-section.js');

View File

@@ -20,7 +20,7 @@ class ServerInfoForm extends BaseComponent {
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-alias">${this.props.server.alias}</span>
<i class="material-icons open-tab-button">open_in_new</i>
<i class="material-icons open-tab-button">open_in_new</i>
</div>
<div class="server-info-row">
<input class="setting-input-value" disabled value="${this.props.server.url}"/>

View File

@@ -15,7 +15,7 @@ class ServersSection extends BaseSection {
template() {
return `
<div class="settings-pane" id="server-settings-pane">
<div class="title">Add Server</div>
<div class="page-title">Register or login to a Zulip organization to get started</div>
<div id="new-server-container"></div>
<div class="title" id="existing-servers"></div>
<div id="server-info-container"></div>
@@ -38,9 +38,9 @@ class ServersSection extends BaseSection {
this.$newServerContainer = document.getElementById('new-server-container');
this.$newServerButton = document.getElementById('new-server-action');
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
this.$serverInfoContainer.innerHTML = servers.length ? '' : '';
// Show Existing servers if servers are there otherwise hide it
this.$existingServers.innerHTML = servers.length === 0 ? '' : 'Existing Servers';
this.$existingServers.innerHTML = servers.length === 0 ? '' : 'Existing organizations';
this.initNewServerForm();
this.$createOrganizationContainer = document.getElementById('create-organization-container');

View File

@@ -1,7 +1,10 @@
'use strict';
const { ipcRenderer } = require('electron');
const { spellChecker } = require('./spellchecker');
const SetupSpellChecker = require('./spellchecker');
const ConfigUtil = require(__dirname + '/utils/config-util.js');
// eslint-disable-next-line import/no-unassigned-import
require('./notification');
@@ -32,8 +35,15 @@ process.once('loaded', () => {
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
// Init spellchecker
spellChecker();
// Get the default language of the server
const serverLanguage = page_params.default_language; // eslint-disable-line no-undef, camelcase
if (serverLanguage) {
// Set spellcheker language
ConfigUtil.setConfigItem('spellcheckerLanguage', serverLanguage);
// Init spellchecker
SetupSpellChecker.init();
}
// redirect users to network troubleshooting page
const getRestartButton = document.querySelector('.restart_get_events_button');
@@ -43,3 +53,10 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
});
// Clean up spellchecker events after you navigate away from this page;
// otherwise, you may experience errors
window.addEventListener('beforeunload', () => {
SetupSpellChecker.unsubscribeSpellChecker();
});

View File

@@ -1,29 +1,56 @@
'use strict';
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
const { SpellCheckHandler, ContextMenuListener, ContextMenuBuilder } = require('electron-spellchecker');
function spellChecker() {
// Implement spellcheck using electron api
window.spellCheckHandler = new SpellCheckHandler();
window.spellCheckHandler.attachToInput();
const ConfigUtil = require(__dirname + '/utils/config-util.js');
// Start off as US English
window.spellCheckHandler.switchLanguage('en-US');
class SetupSpellChecker {
init() {
if (ConfigUtil.getConfigItem('enableSpellchecker')) {
this.enableSpellChecker();
}
this.enableContextMenu();
}
const contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
const contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
enableSpellChecker() {
try {
this.SpellCheckHandler = new SpellCheckHandler();
} catch (err) {
console.log(err);
}
}
// Clean up events after you navigate away from this page;
// otherwise, you may experience errors
window.addEventListener('beforeunload', () => {
// eslint-disable-next-line no-undef
spellCheckHandler.unsubscribe();
contextMenuListener.unsubscribe();
});
enableContextMenu() {
if (this.SpellCheckHandler) {
this.SpellCheckHandler.attachToInput();
const userLanguage = ConfigUtil.getConfigItem('spellcheckerLanguage');
// eslint-disable-next-line no-unused-expressions
process.platform === 'darwin' ?
// On macOS, spellchecker fails to auto-detect the lanugage user is typing in
// that's why we need to mention it explicitly
this.SpellCheckHandler.switchLanguage(userLanguage) :
// On Linux and Windows, spellchecker can automatically detects the language the user is typing in
// and silently switches on the fly; thus we can start off as US English
this.SpellCheckHandler.switchLanguage('en-US');
}
const contextMenuBuilder = new ContextMenuBuilder(this.SpellCheckHandler);
this.contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
}
unsubscribeSpellChecker() {
// eslint-disable-next-line no-undef
if (this.SpellCheckHandler) {
this.SpellCheckHandler.unsubscribe();
}
if (this.contextMenuListener) {
this.contextMenuListener.unsubscribe();
}
}
}
module.exports = {
spellChecker
};
module.exports = new SetupSpellChecker();

View File

@@ -110,9 +110,15 @@ class DomainUtil {
return new Promise((resolve, reject) => {
request(checkDomain, (error, response) => {
const certsError =
['Error: self signed certificate',
'Error: unable to verify the first certificate'
[
'Error: self signed certificate',
'Error: unable to verify the first certificate',
'Error: unable to get local issuer certificate'
];
// If the domain contains following strings we just bypass the server
const whitelistDomains = [
'zulipdev.org'
];
if (!error && response.statusCode !== 404) {
// Correct
this.getServerSettings(domain).then(serverSettings => {
@@ -120,7 +126,7 @@ class DomainUtil {
}, () => {
resolve(serverConf);
});
} else if (certsError.indexOf(error.toString()) >= 0) {
} else if (domain.indexOf(whitelistDomains) >= 0 || certsError.indexOf(error.toString()) >= 0) {
if (silent) {
this.getServerSettings(domain).then(serverSettings => {
resolve(serverSettings);
@@ -152,7 +158,9 @@ class DomainUtil {
});
}
} else {
reject('Not a valid Zulip server');
const invalidZulipServerError = `${domain} does not appear to be a valid Zulip server. Make sure that \
\n(1) you can connect to that URL in a web browser and \n (2) if you need a proxy to connect to the Internet, that you've configured your proxy in the Network settings`;
reject(invalidZulipServerError);
}
});
});

View File

@@ -12,5 +12,5 @@
<div id="settings-container"></div>
</div>
</body>
<script src="js/pages/preference/preference.js"></script>
<script src="js/pages/preference/preference.js"></script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -6,7 +6,7 @@ os: Previous Visual Studio 2015
cache:
- node_modules
install:
- ps: Install-Product node 6 x64
- git reset --hard HEAD
@@ -17,7 +17,7 @@ install:
- npm install
- npm install -g gulp
build: off
build: off
test_script:
- npm run test
- npm run test-all

View File

@@ -1,9 +1,10 @@
'use strict';
const gulp = require('gulp');
const mocha = require('gulp-mocha');
const electron = require('electron-connect').server.create({
verbose: true
});
const tape = require('gulp-tape');
const tapColorize = require('tap-colorize');
gulp.task('dev', () => {
// Start browser process
@@ -28,9 +29,11 @@ gulp.task('reload:renderer', done => {
done();
});
// Test app using mocha+spectron
gulp.task('test', () => {
return gulp.src('tests/index.js').pipe(mocha());
gulp.task('test-e2e', () => {
return gulp.src('tests/e2e/*.js')
.pipe(tape({
reporter: tapColorize()
}));
});
gulp.task('default', ['dev', 'test']);
gulp.task('default', ['dev', 'test-e2e']);

21
karma.conf.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
browsers: ['Electron'],
preprocessors: {
'**/*.js': ['electron']
},
files: [
{pattern: './karma.shim.js', watched: true, included: true, served: true},
{pattern: './tests/unit/*.js', watched: true, included: true, served: true},
{pattern: './app/renderer/**/*.js', watched: true, included: false, served: true}
],
reporters: ['mocha'],
client: {
captureConsole: true,
useIframe: false
},
singleRun: true
});
};

5
karma.shim.js Normal file
View File

@@ -0,0 +1,5 @@
window.require = window.parent.require;
window.process = window.parent.process;
window.__dirname = window.parent.__dirname;
require('module').globalPaths.push('./node_modules');
require('module').globalPaths.push('./app/renderer');

7534
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,14 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "1.5.0",
"version": "1.7.0",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"email": "<svnitakash@gmail.com>",
"copyright": "©2017 Kandra Labs, Inc.",
"copyright": "Kandra Labs, Inc.",
"author": {
"name": "Kandra Labs, Inc.",
"email": "svnitakash@gmail.com"
"email": "support@zulipchat.com"
},
"repository": {
"type": "git",
@@ -22,7 +21,10 @@
"start": "electron app --disable-http-cache",
"reinstall": "rm -rf node_modules; rm -rf app/node_modules; npm install",
"postinstall": "electron-builder install-app-deps",
"test": "xo",
"lint": "xo",
"test-e2e": "gulp test-e2e",
"test-unit": "karma start karma.conf.js",
"test-all": "xo && npm run test-unit && npm run test-e2e",
"dev": "gulp dev",
"pack": "electron-builder --dir",
"dist": "electron-builder",
@@ -30,7 +32,7 @@
"travis": "cd ./scripts && ./travis-build-test.sh"
},
"pre-commit": [
"test"
"lint"
],
"build": {
"appId": "org.zulip.zulip-electron",
@@ -56,7 +58,9 @@
"maintainer": "Akash Nimare <svnitakash@gmail.com>"
},
"deb": {
"synopsis": "Zulip Desktop App"
"synopsis": "Zulip Desktop App",
"afterInstall": "./scripts/debian-add-repo.sh",
"afterRemove": "./scripts/debian-uninstaller.sh"
},
"dmg": {
"background": "build/appdmg.png",
@@ -105,17 +109,27 @@
],
"devDependencies": {
"assert": "1.4.1",
"cp-file": "^5.0.0",
"devtron": "1.4.0",
"electron-builder": "19.29.1",
"electron": "1.6.14",
"electron-builder": "19.46.4",
"electron": "1.7.9",
"electron-connect": "0.6.2",
"electron-debug": "1.4.0",
"gulp": "3.9.1",
"gulp-mocha": "4.3.1",
"chai-as-promised": "7.1.1",
"chai": "4.1.1",
"gulp-tape": "0.0.9",
"is-ci": "^1.0.10",
"jasmine": "^2.8.0",
"karma": "^1.7.1",
"karma-electron": "^5.2.2",
"karma-electron-launcher": "^0.2.0",
"karma-jasmine": "^1.1.0",
"karma-mocha-reporter": "^2.2.5",
"pre-commit": "1.2.2",
"spectron": "3.7.2",
"xo": "0.18.2",
"pre-commit": "1.2.2"
"tap-colorize": "^1.2.0",
"tape": "^4.8.0",
"watchify": "^3.9.0",
"xo": "0.18.2"
},
"xo": {
"parserOptions": {
@@ -148,7 +162,8 @@
}
],
"ignore": [
"tests/*.js"
"tests/e2e/*.js",
"tests/unit/*"
],
"envs": [
"node",

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# This script runs when user install the debian package
# Install apt repository source list if it does not exist
if ! grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep zulip.list; then
sudo apt-key adv --keyserver pool.sks-keyservers.net --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9
echo "deb https://dl.bintray.com/zulip/debian/ stable main" | \
sudo tee -a /etc/apt/sources.list.d/zulip.list;
fi

View File

@@ -0,0 +1,31 @@
#!/bin/bash
# This script runs when user uninstall the debian package.
# It will remove all the config files and anything which was added by the app.
# Remove apt repository source list when user uninstalls Zulip app
if grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep zulip.list; then
sudo apt-key del 69AD12704E71A4803DCA3A682424BE5AE9BD10D9;
sudo rm /etc/apt/sources.list.d/zulip.list;
fi
# Get the root user
if [ $SUDO_USER ];
then getSudoUser=$SUDO_USER;
else getSudoUser=`whoami`;
fi
# Get the path for Zulip's desktop entry which is created by auto-launch script
getDesktopEntry=/home/$getSudoUser/.config/autostart/zulip.desktop;
# Remove desktop entry if exists
if [ -f $getDesktopEntry ]; then
sudo rm $getDesktopEntry;
fi
# App directory which contains all the config, setting files
appDirectory=/home/$getSudoUser/.config/Zulip/;
if [ -d $appDirectory ]; then
sudo rm -rf $appDirectory;
fi

View File

@@ -1,10 +1,23 @@
#!/usr/bin/env bash
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
export {no_proxy,NO_PROXY}="127.0.0.1,localhost"
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
sleep 3
export {no_proxy,NO_PROXY}="127.0.0.1,localhost"
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
sleep 3
echo 'Travis Screen Resolution:'
xdpyinfo | grep dimensions
fi
npm run test
# macOS
# Run all the tests
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
npm run test-all
fi
# Linux
# Only run linting test on Linux
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
npm run lint
fi

5
scripts/travis-xvfb.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16
fi

7
tests/e2e/config.js Normal file
View File

@@ -0,0 +1,7 @@
const path = require('path')
const TEST_APP_PRODUCT_NAME = 'ZulipTest'
module.exports = {
TEST_APP_PRODUCT_NAME
}

13
tests/e2e/index.js Normal file
View File

@@ -0,0 +1,13 @@
const test = require('tape')
const setup = require('./setup')
test('app runs', function (t) {
t.timeoutAfter(10e3)
setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t)
.then(() => app.client.windowByIndex(1)) // focus on webview
.then(() => app.client.waitForExist('//*[@id="new-server-container"]/div/div/div[2]/input'))
.then(() => setup.endTest(app, t),
(err) => setup.endTest(app, t, err || 'error'))
})

99
tests/e2e/setup.js Normal file
View File

@@ -0,0 +1,99 @@
const Application = require('spectron').Application
const cpFile = require('cp-file')
const fs = require('fs')
const isCI = require('is-ci')
const mkdirp = require('mkdirp')
const path = require('path')
const rimraf = require('rimraf')
const config = require('./config')
module.exports = {
createApp,
endTest,
waitForLoad,
wait,
resetTestDataDir
}
// Runs Zulip Desktop.
// Returns a promise that resolves to a Spectron Application once the app has loaded.
// Takes a Tape test. Makes some basic assertions to verify that the app loaded correctly.
function createApp (t) {
generateTestAppPackageJson()
return new Application({
path: path.join(__dirname,'..', '..', 'node_modules', '.bin',
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
args: [path.join(__dirname)], // Ensure this dir has a package.json file with a 'main' entry piont
env: {NODE_ENV: 'test'},
waitTimeout: 10e3
})
}
// Generates package.json for test app
// Reads app package.json and updates the productName to config.TEST_APP_PRODUCT_NAME
// We do this so that the app integration doesn't doesn't share the same appDataDir as the dev application
function generateTestAppPackageJson () {
let packageJson = require(path.join(__dirname, '..', '..', 'package.json'))
packageJson.productName = config.TEST_APP_PRODUCT_NAME
packageJson.main = '../../app/main'
const testPackageJsonPath = path.join(__dirname, 'package.json')
fs.writeFileSync(testPackageJsonPath, JSON.stringify(packageJson, null, ' '), 'utf-8')
}
// Starts the app, waits for it to load, returns a promise
function waitForLoad (app, t, opts) {
if (!opts) opts = {}
return app.start().then(function () {
return app.client.waitUntilWindowLoaded()
})
.then(function() {
return app.client.pause(2000);
})
.then(function () {
return app.webContents.getTitle()
}).then(function (title) {
t.equal(title, 'Zulip', 'html title')
})
}
// Returns a promise that resolves after 'ms' milliseconds. Default: 1 second
function wait (ms) {
if (ms === undefined) ms = 1000 // Default: wait long enough for the UI to update
return new Promise(function (resolve, reject) {
setTimeout(resolve, ms)
})
}
// Quit the app, end the test, either in success (!err) or failure (err)
function endTest (app, t, err) {
return app.stop().then(function () {
t.end(err)
})
}
function getAppDataDir () {
let base
if (process.platform === 'darwin') {
base = path.join(process.env.HOME, 'Library', 'Application Support')
} else if (process.platform === 'linux') {
base = process.env.XDG_CONFIG_HOME ?
process.env.XDG_CONFIG_HOME : path.join(process.env.HOME, '.config')
} else if (process.platform === 'win32') {
base = process.env.APPDATA
} else {
console.log('Could not detect app data dir base. Exiting...')
process.exit(1)
}
console.log('Detected App Data Dir base:', base)
return path.join(base, config.TEST_APP_PRODUCT_NAME)
}
// Resets the test directory, containing domain.json, window-state.json, etc
function resetTestDataDir () {
appDataDir = getAppDataDir()
rimraf.sync(appDataDir)
rimraf.sync(path.join(__dirname, 'package.json'))
}

View File

@@ -0,0 +1,19 @@
const test = require('tape')
const setup = require('./setup')
test('add-organization', function (t) {
t.timeoutAfter(50e3)
setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t)
.then(() => app.client.windowByIndex(1)) // focus on webview
.then(() => app.client.setValue('.setting-input-value', 'chat.zulip.org'))
.then(() => app.client.click('.server-save-action'))
.then(() => setup.wait(5000))
.then(() => app.client.windowByIndex(0)) // Switch focus back to main win
.then(() => app.client.windowByIndex(1)) // Switch focus back to org webview
.then(() => app.client.waitForExist('//*[@id="id_username"]'))
.then(() => setup.endTest(app, t),
(err) => setup.endTest(app, t, err || 'error'))
})

View File

@@ -1,81 +0,0 @@
const assert = require('assert')
const Application = require('spectron').Application
const chai = require('chai')
const { expect } = chai
const chaiAsPromised = require('chai-as-promised')
chai.should()
chai.use(chaiAsPromised)
describe('application launch', function () {
this.timeout(15000)
beforeEach(function () {
this.app = new Application({
path: require('electron'),
args: [__dirname + '/../app/renderer/main.html']
})
return this.app.start()
})
beforeEach(function () {
chaiAsPromised.transferPromiseness = this.app.transferPromiseness
})
afterEach(function () {
if (this.app && this.app.isRunning()) {
return this.app.stop()
}
})
it('shows an initial window', function () {
return this.app.client.waitUntilWindowLoaded(5000)
.getWindowCount().should.eventually.equal(2)
.browserWindow.isMinimized().should.eventually.be.false
.browserWindow.isDevToolsOpened().should.eventually.be.false
.browserWindow.isVisible().should.eventually.be.true
.browserWindow.isFocused().should.eventually.be.true
.browserWindow.getBounds().should.eventually.have.property('width').and.be.above(0)
.browserWindow.getBounds().should.eventually.have.property('height').and.be.above(0)
})
it('sets up a default organization', function () {
let app = this.app
let self = this
app.client.execute(() => {
window.confirm = function () { return true }
})
function createOrg (client, name, url, winIndex) {
return client
// Focus on settings webview
.then(switchToWebviewAtIndex.bind(null, self.app.client, winIndex))
.pause(1000) // wait for settings to load
// Fill settings form
.click('#new-server-action')
.setValue('input[id="server-info-name"]', name)
.setValue('input[id="server-info-url"]', url)
.click('#save-server-action')
.pause(500) // Need to pause while server verification takes place
.then(() => app.browserWindow.reload())
.pause(1500) // Wait for webview of org to load
}
function switchToWebviewAtIndex(client, index) {
return client
.windowHandles()
.then(function (session) {
this.window(session.value[index])
})
}
return this.app.client.waitUntilWindowLoaded(5000)
.then(() => createOrg(self.app.client, 'Zulip 1', 'chat.zulip.org', 1))
.then(switchToWebviewAtIndex.bind(null, self.app.client, 0))
.click('#add-action > i').pause(500)
.then(switchToWebviewAtIndex.bind(null, self.app.client, 2))
.then(() => createOrg(self.app.client, 'Zulip 2', 'chat.zulip.org', 2))
})
})

View File

@@ -0,0 +1,20 @@
const ConfigUtil = require('js/utils/config-util.js');
const SetupSpellChecker = require('js/spellchecker')
describe('test spell checker', function () {
// enable spellchecker settings
ConfigUtil.setConfigItem('enableSpellchecker', true);
ConfigUtil.setConfigItem('spellcheckerLanguage', 'en');
SetupSpellChecker.init() // re-initialize after setting update
const spellCheckHandler = SetupSpellChecker.SpellCheckHandler
it('mark misspelled word', function () {
expect(spellCheckHandler.isMisspelled('helpe')).toBe(true)
})
it('verify properly spelled word', function () {
expect(spellCheckHandler.isMisspelled('help')).toBe(false)
})
})

View File

@@ -5,7 +5,11 @@
* Electron is more or less Chrome, you can get developer tools using `CMD+ALT+I`
### Error : ChecksumMismatchError
- Try deleteing `node_modules` && `app/node_modules` directories. Re-install dependencies using `npm install`.
- Try deleteing `node_modules` && `app/node_modules` directories. Re-install dependencies using `npm install`
### Error : Module version mismatch. Expected 50, got 51
- Make sure you have installed [node-gyp](https://github.com/nodejs/node-gyp#installation) dependencies properly.
- Make sure you have installed [node-gyp](https://github.com/nodejs/node-gyp#installation) dependencies properly
### Error: Desktop Notifications not working
- Make sure the **Show Desktop Notifications** setting option is set to be true
- Check your OS notifications center settings