Compare commits

...

156 Commits

Author SHA1 Message Date
Akash Nimare
3dade768a7 Merge pull request #141 from Lplenka/Certificate_Issue
 Added support for self-signed certificate fixes #126
2017-04-28 02:46:18 +05:30
Lalu Prasad Lenka
7b3c7ba5fa Merge branch 'master' into Certificate_Issue 2017-04-28 02:28:12 +05:30
Akash Nimare
616bc0f73b Merge pull request #144 from Lplenka/offline
Fixed internet connectivity error on Linux
2017-04-28 02:23:46 +05:30
Lplenka
8ecdf1f18a Update PR #115 code clean-up 2017-04-28 01:50:23 +05:30
Lplenka
d2daa65059 Update PR #115 Added ERR_NAME_NOT_RESOLVED condition 2017-04-28 00:38:55 +05:30
Lplenka
487ee538e3 Lint error fix 🔧 2017-04-27 12:54:31 +05:30
Lplenka
6382c6d2b3 Improved PR #115 2017-04-27 12:50:53 +05:30
Lplenka
cbcff67d28 [WIP] issue #126, now not remembering servers 2017-04-21 18:39:58 +05:30
akashnimare
61a429365b support self-signed cert fixing #126 [WIP] 2017-04-18 04:57:33 +05:30
akashnimare
e55f38a962 🚚 moved files to renderer 2017-04-18 04:17:32 +05:30
akashnimare
81798583ae unused tray.js from main process deleted + travis test 2017-04-18 04:04:15 +05:30
akashnimare
9cab61cebc 🎉 bump v0.5.10 2017-04-18 00:40:22 +05:30
Akash Nimare
f290732cb6 Merge pull request #134 from Lplenka/master
Added unread counts in tray icon Fixes #110
2017-04-18 00:26:36 +05:30
Lplenka
2dd44852fa Lint error fixed #126[WIP] 2017-04-17 14:22:30 +05:30
Lplenka
bd2f17deec Removed Error from console #126[WIP] 2017-04-17 12:55:41 +05:30
Lplenka
06faf46bcc Support for Switching to server with certificate error #126[WIP] 2017-04-17 12:39:54 +05:30
Lplenka
468e9d539b issue #126 [WIP] 2017-04-17 12:15:07 +05:30
akashnimare
449f407236 Enable cache on travis 2017-04-17 00:20:51 +05:30
Lplenka
7efe90e709 🔧 Lint Error fixed 2017-04-14 09:16:09 +05:30
Lalu Prasad Lenka
184e1a5bc4 Merge branch 'master' into master 2017-04-14 08:20:29 +05:30
Akash Nimare
85e7b337a7 Fixing travis test [WIP] 2017-04-14 06:37:08 +05:30
akashnimare
83759bde1c using known working version for devdependencies 2017-04-14 05:11:51 +05:30
akashnimare
d9b1d45e0e 🔧 fix linting errors 2017-04-14 04:54:44 +05:30
Akash Nimare
df91c20f36 Merge pull request #137 from brockwhittaker/landing-page-redesign
Redesign the landing page to look more inline with brand design.
2017-04-14 04:30:26 +05:30
brockwhittaker
c1f6159d69 Redesign the landing page to look more inline with brand design.
This redesigns the landing page to incorporate the Zulip style guide.
This also adds two animations:

1. The error text slides down on error and back up when typing.
2. The form section shakes when there is invalid input for 0.5s.
2017-04-13 12:03:45 -07:00
Akash Nimare
5a0461211a remove typo 2017-04-13 01:38:41 +05:30
Akash Nimare
1394f790c3 Merge pull request #136 from brockwhittaker/master
about: Restyle Electron => Zulip desktop page.
2017-04-13 01:06:05 +05:30
brockwhittaker
4d374ff40c Restyle Electron => Zulip desktop page.
This restyles the "about" page to look slicker and have brand colors.
2017-04-12 12:24:27 -07:00
akashnimare
0d15435408 🔖 v0.5.9 2017-04-11 01:54:39 +05:30
Lalu Prasad Lenka
d4448ba086 Merge branch 'master' into master 2017-04-09 10:02:42 +05:30
akashnimare
4bd6fde5b6 remove unused dependency configstore 2017-04-09 02:37:12 +05:30
Akash Nimare
e5097ace06 📝 use nvm to install nodejs #135 2017-04-05 19:48:13 +05:30
Lplenka
ca078cbbfd Fixed size bug in Mac OS #110 [WIP] 2017-04-02 13:29:14 +05:30
Lplenka
6d45105b69 Fixed bug in Mac OS #110 [WIP] 2017-04-02 13:24:56 +05:30
Lplenka
40f81af2dd Lint error fixed #110 [WIP] 2017-04-02 11:06:39 +05:30
Lalu Prasad Lenka
d5e6184e75 Fixed bugs in Windows #110 [WIP] 2017-04-02 05:09:43 +05:30
Lplenka
0ec38ba41d Added function to set tray size according to OS, fixed toggle tray 2017-04-02 09:33:13 +05:30
Lplenka
460a64710a Js Lint error fixed 🔧, Fixes #110 2017-04-02 07:40:29 +05:30
Lplenka
9ec62a748f Added communication b/w Main & Renderer process for proper functioning of Tray icon #110 [WIP] 2017-04-02 01:21:33 +05:30
Lplenka
a7a80cef99 Added Tray.js to renderer js files 2017-04-02 00:55:48 +05:30
akashnimare
bcaf54b349 🔥 remove macOs swipe navigation 2017-04-01 11:19:39 -07:00
akashnimare
1f6d0762bb 🐛 fixing configstore permission issue on windows #125 [WIP] 2017-04-01 10:47:52 -07:00
akashnimare
1aa1655676 🔧 update electron-builder/updater to latest fixes #133 2017-03-31 02:02:47 +05:30
akashnimare
0ad66399d0 🐛 set valid config #133 2017-03-31 01:23:44 +05:30
akashnimare
3a6bb14224 🐛 fixing dmg build failed [WIP] #133 2017-03-31 00:47:26 +05:30
Akash Nimare
53eb8051ad Update CONTRIBUTING.md 2017-03-23 15:45:30 +05:30
Akash Nimare
ed9174f57c Merge pull request #119 from sumedh123/master
updated contributing guide
2017-03-23 15:44:10 +05:30
Akash Nimare
260d6a1906 Updated community section 2017-03-23 15:42:27 +05:30
Akash Nimare
dc53319c8e 🆙 bump electron-spellcheck to v1.0.5 2017-03-21 00:43:10 +05:30
Akash Nimare
77369536b3 Merge pull request #130 from Lplenka/master
Check if zulip server is down Fixes Issue #124
2017-03-20 12:31:18 +05:30
Lplenka
531afcb1e5 Fixed root directory's package.json 2017-03-19 17:33:53 +05:30
Lplenka
d6c4eeccf8 Code formatting done 2017-03-19 01:23:13 +05:30
Lplenka
496b906fd0 Merge branch 'master' of https://github.com/Lplenka/zulip-electron 2017-03-19 01:18:32 +05:30
Lplenka
1be29faea6 Removed spaces from imported/exported varibles & fixed the package.json in app folder 2017-03-19 01:16:07 +05:30
Akash Nimare
bc9a7c9890 update copyright 2017-03-19 00:50:50 +05:30
Lplenka
5745276dbb Code formatting done Fixes #124 2017-03-18 13:20:15 +05:30
Lplenka
acf0282aa0 Checks Server error while switching server 2017-03-18 12:40:38 +05:30
Lplenka
54d942178a Implemented function in index to check server error while loading 2017-03-18 12:32:43 +05:30
Lplenka
d84ada373e Added https node module 2017-03-18 12:22:29 +05:30
Lplenka
d4d36d0582 Removed reductant call to prefDomain() 2017-03-18 12:14:12 +05:30
Lplenka
63e6c634b9 Added Node global symbols to avoid setImmdediate Reference Error 2017-03-18 12:11:45 +05:30
Lplenka
4bc558cdbc Merge branch 'master' of https://github.com/Lplenka/zulip-electron 2017-03-18 09:04:19 +05:30
Cynthia Lin
34293fd66b Enable zulipbot build notifications.
PRs labeled with the *travis updates* label will receive build notifications from zulipbot.
2017-03-18 08:52:52 +05:30
Akash Nimare
5eba4b8200 Merge pull request #129 from synicalsyntax/patch-1
Enable zulipbot build notifications.
2017-03-18 00:48:47 +05:30
Akash Nimare
a949307820 Merge pull request #128 from Lplenka/master
show window when the web page has been rendered and window can be displayed without a visual flash.
2017-03-18 00:28:16 +05:30
Cynthia Lin
a714977b5a Enable zulipbot build notifications.
PRs labeled with the *travis updates* label will receive build notifications from zulipbot.
2017-03-11 11:46:43 -08:00
Lplenka
bfcaa51c46 🐛 🔧 linting error fixed 2017-03-11 01:55:48 +05:30
Lplenka
d7d3017bc1 Bug Fixes 2017-03-11 01:46:35 +05:30
Lalu Prasad Lenka
c7ce8fb7c8 Merge pull request #2 from zulip/master
Merging with zulip-electron origin
2017-03-07 13:42:02 +05:30
Sumedh Nimkarde
65a80de01d update Community section 2017-03-07 07:52:30 +05:30
akashnimare
f6bf210451 🔨 fixed linting errors 2017-03-06 15:18:52 +05:30
Akash Nimare
8c23ec3417 Merge pull request #122 from geeeeeeeeek/feature/#104-add-option-to-hide-tray-icon
#104 Add a menu item to toggle the tray icon.
2017-03-06 15:01:50 +05:30
Akash Nimare
97bbd809f7 Merge pull request #121 from geeeeeeeeek/bugfix/#120-fix-error-launching
#120 Fix error launching caused by missing  keyword.
2017-03-06 14:31:38 +05:30
Akash Nimare
76381cac08 Merge pull request #118 from Lplenka/master
Added localhost support fixes #78
2017-03-06 14:30:29 +05:30
Sumedh Nimkarde
13c4ceedc2 add Community section 2017-03-05 22:47:43 +05:30
Sumedh Nimkarde
f0889edf9c add zulipbot link 2017-03-05 15:38:18 +05:30
Zhongyi Tong
ab8367c946 #104 Add a menu item to toggle the tray icon. 2017-03-05 00:54:55 +08:00
Zhongyi Tong
c5887c8f71 #120 Fix error launching caused by missing keyword. 2017-03-04 23:46:26 +08:00
Sumedh Nimkarde
7b7ab03d0b add Chat section 2017-03-04 11:23:20 +05:30
Lplenka
394caa7934 Issue fix in better way 2017-03-04 10:02:27 +05:30
Lplenka
db2860b53e code formatting done 2017-03-04 01:32:34 +05:30
Lplenka
6d20df3557 Changed error message 2017-03-04 01:01:31 +05:30
Lplenka
2942cd1244 merge conflicts resolved 2017-03-04 00:44:40 +05:30
Lplenka
174049f489 issue #78 fixed 2017-03-04 00:16:41 +05:30
Lalu Prasad Lenka
21eae28999 Merge pull request #1 from zulip/master
Update from Original
2017-03-03 11:04:39 +05:30
akashnimare
f256cbcd5d Added error message when input url is null fixes #116 2017-03-02 17:35:20 +05:30
akashnimare
ff8c20f0b4 Removed unnessary code #116 2017-03-02 17:08:42 +05:30
akashnimare
9e0c17a793 🐛 fixing it in preference window #116 2017-03-02 17:05:01 +05:30
akashnimare
b4fb00aa52 🐛 show error message if input server url is null #116 2017-03-02 16:47:41 +05:30
akashnimare
13d0b5e51c Fixed linting error 2017-03-02 16:00:33 +05:30
Akash Nimare
dc15e4578c Merge pull request #115 from jajodiaraghav/offline
Display an error message if internet not working.
2017-03-02 15:36:19 +05:30
Raghav Jajodia
673da66ee9 Display error message if internet not working.
An error message with 'Try again' option is displayed
if the internet is not working.
Fixes #114
2017-02-28 23:01:13 +05:30
Akash Nimare
e397e9bfb4 Merge pull request #113 from chiragjn/master
Fix issue #112 for displaying Keyboard shortcuts
2017-02-24 14:35:48 +05:30
Chirag Jain
4eca2e9254 Fix lint errors 2017-02-24 11:31:10 +05:30
Chirag Jain
a1407826b6 Fix issue #112 for displaying Keyboard shortcuts 2017-02-24 10:57:29 +05:30
akashnimare
6d8f83798b 📦 update dependencies 2017-02-24 02:34:42 +05:30
akashnimare
bfc03c7e95 🐛 fix useragent + notifications #108 + #111 2017-02-24 02:30:13 +05:30
akashnimare
06737ce629 👌 detect Windows version (7/10) #108 2017-02-21 01:04:24 +05:30
akashnimare
6b09840347 improving usergent #108 2017-02-21 00:29:20 +05:30
akashnimare
19b5eecdcd Check if webview's url is failing travis tests on linux [WIP] #109 2017-02-18 16:51:31 +05:30
akashnimare
f443918433 🔧 added spellchecker dependencies in travis 🐧 2017-02-18 16:10:54 +05:30
akashnimare
bb74e58d63 🎨 fixed linting + #108 2017-02-18 15:56:41 +05:30
akashnimare
612e670bb5 🐛 added app version + os details in useragent #108 2017-02-18 15:17:30 +05:30
akashnimare
34bb55cb9f 🐛 set user-agent to ZulipElectron/version #108 2017-02-17 15:39:06 +05:30
akashnimare
1457e82649 📦 updated dependencies 2017-02-17 00:15:14 +05:30
akashnimare
0bdeaaba18 removed unused dependency dialogs 2017-02-17 00:02:27 +05:30
akashnimare
e2286b6110 🚀 windows build script + nsis web installer 2017-02-14 00:28:06 +05:30
akashnimare
27ba3f3068 removed squirrel events code 2017-02-14 00:22:40 +05:30
akashnimare
9859315fea improve logging in autoupdater[WIP] 2017-02-13 23:54:47 +05:30
akashnimare
73d18dde9e init v0.5.8 + updated dependencies 2017-02-13 20:13:33 +05:30
akashnimare
0372befc5a bump version v0.5.7 2017-02-08 10:37:02 +05:30
akashnimare
063799a053 Updated login page title + placeholder 2017-02-07 18:37:14 +05:30
akashnimare
297b307726 update electron-builder to v13.0.0 2017-02-07 14:20:43 +05:30
akashnimare
deed66973f update electron-builder to v13.0.0 2017-02-07 14:20:17 +05:30
akashnimare
03486e438d remove release name+notes details from autoupdater 2017-02-07 14:17:04 +05:30
Akash Nimare
e113f59aad Bump electron-builder to 12.3.1 2017-02-06 02:30:35 +05:30
Akash Nimare
29ece4824a Merge pull request #105 from zulip/nsis
🎉 switched to NSIS + autoupdates
2017-02-06 01:23:55 +05:30
akashnimare
66c62c55e2 fixed logger undefined error 2017-02-06 01:09:03 +05:30
akashnimare
40852942d2 fixed releaseName undefined error 2017-02-02 16:41:52 +05:30
akashnimare
15c8591691 windows installer >> install per all users 2017-02-02 16:16:32 +05:30
akashnimare
e21902a5e3 🆙 electron-updater to 1.4.1 2017-02-02 15:37:10 +05:30
akashnimare
a5d42e8ccd log whats happening in auto-updater 2017-02-02 12:06:13 +05:30
akashnimare
0923df7250 import autoupdater 2017-02-02 11:52:27 +05:30
akashnimare
37f5258210 updated to electron-builder's latest version 2017-02-02 11:07:31 +05:30
akashnimare
19819f7d48 squirrel startup is not needed for NSIS 2017-01-28 21:21:52 +05:30
akashnimare
40f74cdac2 removed auto updater feed 2017-01-28 13:44:07 +05:30
akashnimare
e4ba3b9721 Added electron-updater dependency autoupdates 2017-01-28 13:21:41 +05:30
akashnimare
9a221585b9 set target to NSIS 2017-01-27 11:23:13 +05:30
Akash Nimare
069a0ff306 Added iconUrl to win.build 2017-01-26 02:10:17 +05:30
akashnimare
3153fb91da 🚀 Added back/forward navigation 2017-01-26 01:30:21 +05:30
Akash Nimare
92d4d27fa8 Added app icon >> windows installer 2017-01-26 00:50:50 +05:30
Akash Nimare
209fc4a65c Added squirrel-windows dependency 2017-01-26 00:47:55 +05:30
Akash Nimare
5e9ecedecd Updated electron-builder to v11.5.1 2017-01-25 23:48:30 +05:30
Akash Nimare
613df32bf1 Updated Prerequisites 2017-01-25 23:03:35 +05:30
Akash Nimare
7606f37695 Merge pull request #102 from zulip/dev
update spellchecker to v1.0.0
2017-01-25 22:55:36 +05:30
akashnimare
a2f758a46b spellchecker v1.0.0 2017-01-24 13:03:05 +05:30
akashnimare
2a477abe5f Added log-out shortcut 2017-01-14 23:43:09 +05:30
akashnimare
5f027820f4 ✏️ small typos fixed 2017-01-14 22:42:28 +05:30
Akash Nimare
9e75861546 Fixing travis test (linux) 2017-01-07 17:50:56 +05:30
akashnimare
4060596474 🎨 fixed linting errors 2017-01-07 17:27:54 +05:30
Akash Nimare
2e5888c8af Merge pull request #96 from jajodiaraghav/add_clear_cache_option
Added Clear-cache option in menu
2017-01-07 17:07:09 +05:30
Raghav Jajodia
03d1188e14 Added clear cache option 2017-01-07 17:00:03 +05:30
Raghav Jajodia
c91b0c209a Added clear cache option 2017-01-07 15:58:19 +05:30
Akash Nimare
531973194c Use stable module version
Using stable version of node modules. 
Using '*' or 'latest' in node modules version could cause unexpected results and could break your code.
2017-01-03 15:14:56 +05:30
akashnimare
4d1face275 Removed electron-context-menu 2017-01-03 14:45:04 +05:30
akashnimare
ca7503f1f0 using electron-builder v10.15.1 2017-01-03 14:42:52 +05:30
Akash Nimare
9c163b4166 Merge pull request #97 from zulip/dev
export spellchecker function
2017-01-02 19:19:11 +05:30
akashnimare
742afb1c09 export spellchecker function 2017-01-02 19:15:08 +05:30
Raghav Jajodia
f9f70f001b Added clear cache option 2017-01-02 13:50:19 +05:30
akashnimare
edf34efd86 Removed unnecessary dep. electron-dl 2016-12-31 22:26:42 +05:30
akashnimare
72ebed95da v0.5.4 2016-12-31 22:17:51 +05:30
Akash Nimare
975a6ab8bf electron-spellchecker
Downgrading since v0.7.1 is not working properly on linux.
2016-12-31 22:06:19 +05:30
akashnimare
3352301b67 :head_bandage: update electron-spellchecker 2016-12-31 20:28:09 +05:30
Akash Nimare
358260f766 Update README.md 2016-12-30 03:14:32 +05:30
Akash Nimare
b58052ce34 Merge pull request #94 from GervaisdeM/launch-script-tweak
rename zulip-electron-updater-and-launcher.sh to
2016-12-29 07:29:16 +05:30
GervaisdeM
de9ad8082b rename zulip-electron-updater-and-launcher.sh to
zulip-electron-launcher.sh

changed `npm upgrade` to `npm install`
2016-12-27 00:39:06 -04:00
30 changed files with 922 additions and 688 deletions

View File

@@ -5,6 +5,14 @@ os:
- osx
- linux
addons:
apt:
packages:
- build-essential
- libxext-dev
- libxtst-dev
- libxkbfile-dev
language: node_js
node_js:
- '6'
@@ -17,8 +25,12 @@ cache:
directories:
- node_modules
- app/node_modules
- $HOME/.electron
- $HOME/.cache
script:
- npm run travis
notifications:
webhooks:
urls:
- https://zulip.org/zulipbot/travis
on_success: always
on_failure: always

View File

@@ -1,16 +1,24 @@
#Contributing Guidelines
# Contributing Guidelines
Thanks for taking the time to contribute!
The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgement and feel free to propose changes to this document in a pull request.
## Getting Started
Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron please head over to [this](http://jlord.us/essential-electron/) great article.
## Community
* The whole zulip documentation such as development environment, setting up with zulip project, testing, code of conduct can be read [here](https://zulip.readthedocs.io).
* If you have any questions regarding zulip-electron, open an [issue](https://github.com/zulip/zulip-electron/issues/new/) or ask it [here](https://chat.zulip.org/#narrow/stream/electron).
## Issue
Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/zulip/zulip-electron/issues). If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/zulip/zulip-electron/issues/new). Please pay attention to following points while opening an issue.
The [Zulipbot](https://github.com/zulip/zulipbot) helps to claim the issue by commenting the following in the comment section: "**@zulipbot** claim". **@zulipbot** will assign you to the issue and label the issue as **in progress**. For more details, check out [**@zulipbot**](https://github.com/zulip/zulipbot).
### Does it happen on web browsers? (especially Chrome)
Zulip-Desktop is based on Electron, which integrates the Chrome engine within a standalone application.
If the problem you encounter can be reproduced on web browsers, it may be an issue with Zulip web app.

View File

@@ -13,11 +13,13 @@ multi-account, auto-updates etc.
## Prerequisites
* node >= v6.3.1
* npm >= 3.10.3
* If you're on Debian or Ubuntu, you'll also need to install
`nodejs-legacy`:
> Use [nvm](https://github.com/creationix/nvm) to install the current stable version of node
* python (v2.7.x recommended)
* If you're on Debian or Ubuntu, you'll need to install following packages:
```sh
$ sudo apt-get install nodejs-legacy
$ sudo apt-get install build-essential libxext-dev libxtst-dev libxkbfile-dev
```
## Installation
@@ -61,7 +63,7 @@ You can create Windows installer only when running on Windows, the same is true
- [x] Native Notifications
- [x] SpellChecker
- [x] OSX/Win/Linux installer
- [x] Automatic Updates (macOS)
- [x] Automatic Updates (macOS/Windows)
- [x] Keyboard shortcuts
Description | Keys

View File

@@ -1,50 +1,47 @@
'use strict';
const os = require('os');
const {app, autoUpdater, dialog} = require('electron');
const version = app.getVersion();
const platform = os.platform() + '_' + os.arch(); // usually returns darwin_64
const updaterFeedURL = 'http://zulipdesktop.herokuapp.com/update/' + platform + '/' + version;
const {app, dialog} = require('electron');
const {autoUpdater} = require('electron-updater');
function appUpdater() {
autoUpdater.setFeedURL(updaterFeedURL);
// Log whats happening
// TODO send autoUpdater events to renderer so that we could
// it could console log in developer tools
autoUpdater.on('error', err => console.log(err));
autoUpdater.on('checking-for-update', () => console.log('checking-for-update'));
autoUpdater.on('update-available', () => console.log('update-available'));
autoUpdater.on('update-not-available', () => console.log('update-not-available'));
const log = require('electron-log');
log.transports.file.level = 'info';
autoUpdater.logger = log;
/*
AutoUpdater.on('error', err => log.info(err));
autoUpdater.on('checking-for-update', () => log.info('checking-for-update'));
autoUpdater.on('update-available', () => log.info('update-available'));
autoUpdater.on('update-not-available', () => log.info('update-not-available'));
*/
// Ask the user if update is available
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
let message = app.getName() + ' ' + releaseName + ' is now available. It will be installed the next time you restart the application.';
if (releaseNotes) {
const splitNotes = releaseNotes.split(/[^\r]\n/);
message += '\n\nRelease notes:\n';
splitNotes.forEach(notes => {
message += notes + '\n\n';
});
}
// eslint-disable-next-line no-unused-vars
autoUpdater.on('update-downloaded', (event, info) => {
// Let message = app.getName() + ' ' + info.releaseName + ' is now available. It will be installed the next time you restart the application.';
// if (info.releaseNotes) {
// const splitNotes = info.releaseNotes.split(/[^\r]\n/);
// message += '\n\nRelease notes:\n';
// splitNotes.forEach(notes => {
// message += notes + '\n\n';
// });
// }
// Ask user to update the app
dialog.showMessageBox({
type: 'question',
buttons: ['Install and Relaunch', 'Later'],
defaultId: 0,
message: 'A new version of ' + app.getName() + ' has been downloaded',
detail: message
detail: 'It will be installed the next time you restart the application'
}, response => {
if (response === 0) {
setTimeout(() => autoUpdater.quitAndInstall(), 1);
}
});
});
// init for updates
// Init for updates
autoUpdater.checkForUpdates();
}
exports = module.exports = {
module.exports = {
appUpdater
};

View File

@@ -1,36 +0,0 @@
const {app} = require('electron').remote;
const ipcRenderer = require('electron').ipcRenderer;
const JsonDB = require('node-json-db');
const request = require('request');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
const data = db.getData('/');
console.log(data.domain);
// if (data.domain && window.location.href.indexOf(data.domain) === -1) {
// window.location.href = data.domain
// }
// require('electron-connect').client.create();
window.addDomain = function () {
document.getElementById('main').innerHTML = 'checking...';
let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, '');
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
document.getElementById('main').innerHTML = 'Connect';
document.getElementById('server-status').innerHTML = 'Not a vaild Zulip Server.';
}
});
};

View File

@@ -1,14 +1,17 @@
'use strict';
const path = require('path');
const fs = require('fs');
const os = require('os');
const electron = require('electron');
const {app} = require('electron');
const ipc = require('electron').ipcMain;
const {dialog} = require('electron');
const https = require('https');
const http = require('http');
const electronLocalshortcut = require('electron-localshortcut');
const Configstore = require('configstore');
const Configstore = require('electron-config');
const JsonDB = require('node-json-db');
const isDev = require('electron-is-dev');
const tray = require('./tray');
const appMenu = require('./menu');
const {linkIsInternal, skipImages} = require('./link-helper');
const {appUpdater} = require('./autoupdater');
@@ -16,17 +19,31 @@ const {appUpdater} = require('./autoupdater');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
const data = db.getData('/');
// Handling squirrel.windows events on windows
if (require('electron-squirrel-startup')) {
app.quit();
}
// adds debug features like hotkeys for triggering dev tools and reload
// Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
const conf = new Configstore('Zulip-Desktop');
const conf = new Configstore();
// prevent window being garbage collected
function userOS() {
if (os.platform() === 'darwin') {
return 'Mac';
}
if (os.platform() === 'linux') {
return 'Linux';
}
if (os.platform() === 'win32' || os.platform() === 'win64') {
if (parseFloat(os.release()) < 6.2) {
return 'Windows 7';
} else {
return 'Windows 10';
}
}
}
// Setting userAgent so that server-side code can identify the desktop app
const isUserAgent = 'ZulipElectron/' + app.getVersion() + ' ' + userOS();
// Prevent window being garbage collected
let mainWindow;
let targetLink;
@@ -40,6 +57,73 @@ const targetURL = function () {
return data.domain;
};
function serverError(targetURL) {
if (targetURL.indexOf('localhost:') < 0 && data.domain) {
const req = https.request(targetURL + '/static/audio/zulip.ogg', res => {
console.log('Server StatusCode:', res.statusCode);
console.log('You are connected to:', res.req._headers.host);
if (res.statusCode >= 500 && res.statusCode <= 599) {
return dialog.showErrorBox('SERVER IS DOWN!', 'We are getting a ' + res.statusCode + ' error status from the server ' + res.req._headers.host + '. Please try again after some time or you may switch server.');
}
});
req.on('error', e => {
if (e.toString().indexOf('Error: self signed certificate') >= 0) {
const url = targetURL.replace(/^https?:\/\//, '');
console.log('Server StatusCode:', 200);
console.log('You are connected to:', url);
} else {
console.error(e);
}
});
req.end();
} else if (data.domain) {
const req = http.request(targetURL + '/static/audio/zulip.ogg', res => {
console.log('Server StatusCode:', res.statusCode);
console.log('You are connected to:', res.req._headers.host);
});
req.on('error', e => {
console.error(e);
});
req.end();
}
}
function checkConnectivity() {
return dialog.showMessageBox({
title: 'Internet connection problem',
message: 'No internet available! Try again?',
type: 'warning',
buttons: ['Try again', 'Close'],
defaultId: 0
}, index => {
if (index === 0) {
mainWindow.webContents.reload();
mainWindow.webContents.send('destroytray');
}
if (index === 1) {
app.quit();
}
});
}
const connectivityERR = [
'ERR_INTERNET_DISCONNECTED',
'ERR_PROXY_CONNECTION_FAILED',
'ERR_CONNECTION_RESET',
'ERR_NOT_CONNECTED',
'ERR_NAME_NOT_RESOLVED'
];
function checkConnection() {
// eslint-disable-next-line no-unused-vars
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
const hasConnectivityErr = (connectivityERR.indexOf(errorDescription) >= 0);
if (hasConnectivityErr) {
console.error('error', errorDescription);
checkConnectivity();
}
});
}
const isAlreadyRunning = app.makeSingleInstance(() => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
@@ -72,8 +156,8 @@ const iconPath = () => {
};
function onClosed() {
// dereference the window
// for multiple windows store them in an array
// Dereference the window
// For multiple windows, store them in an array
mainWindow = null;
}
@@ -88,6 +172,7 @@ function updateDockBadge(title) {
if (process.platform === 'darwin') {
app.setBadgeCount(messageCount);
}
mainWindow.webContents.send('tray', messageCount);
}
function createMainWindow() {
@@ -100,14 +185,24 @@ function createMainWindow() {
minWidth: 600,
minHeight: 400,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
preload: path.join(__dirname, '../renderer/js/preload.js'),
plugins: true,
allowDisplayingInsecureContent: true,
nodeIntegration: false
}
},
show: false
});
win.once('ready-to-show', () => {
win.show();
});
serverError(targetURL());
win.loadURL(targetURL(), {
userAgent: isUserAgent + ' ' + win.webContents.getUserAgent()
});
win.loadURL(targetURL());
win.on('closed', onClosed);
win.setTitle('Zulip');
@@ -137,7 +232,7 @@ function createMainWindow() {
});
});
// on osx it's 'moved'
// On osx it's 'moved'
win.on('move', function () {
const pos = this.getPosition();
conf.set({
@@ -146,20 +241,54 @@ function createMainWindow() {
});
});
// stop page to update it's title
// Stop page to update it's title
win.on('page-title-updated', (e, title) => {
e.preventDefault();
updateDockBadge(title);
});
// To destroy tray icon when navigate to a new URL
win.webContents.on('will-navigate', e => {
if (e) {
win.webContents.send('destroytray');
}
});
return win;
}
// TODO - fix certificate errors
app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
// app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
// For self-signed certificate
ipc.on('certificate-err', (e, domain) => {
const detail = `URL: ${domain} \n Error: Self-Signed Certificate`;
dialog.showMessageBox(mainWindow, {
title: 'Certificate error',
message: `Do you trust certificate from ${domain}?`,
// eslint-disable-next-line object-shorthand
detail: detail,
type: 'warning',
buttons: ['Yes', 'No'],
cancelId: 1
// eslint-disable-next-line object-shorthand
}, response => {
if (response === 0) {
// eslint-disable-next-line object-shorthand
db.push('/domain', domain);
mainWindow.loadURL(domain);
}
});
});
// 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
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
if (process.platform !== 'darwin') {
app.quit();
@@ -175,13 +304,14 @@ app.on('activate', () => {
app.on('ready', () => {
electron.Menu.setApplicationMenu(appMenu);
mainWindow = createMainWindow();
tray.create(mainWindow);
// Not using for now // tray.create();
const page = mainWindow.webContents;
// TODO - use global shortcut instead
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
mainWindow.reload();
mainWindow.webContents.send('destroytray');
});
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
@@ -197,7 +327,7 @@ app.on('ready', () => {
});
page.on('dom-ready', () => {
page.insertCSS(fs.readFileSync(path.join(__dirname, 'preload.css'), 'utf8'));
page.insertCSS(fs.readFileSync(path.join(__dirname, '../renderer/css/preload.css'), 'utf8'));
mainWindow.show();
});
@@ -213,27 +343,32 @@ app.on('ready', () => {
page.once('did-frame-finish-load', () => {
const checkOS = isWindowsOrmacOS();
if (checkOS && !isDev) {
// Initate auto-updates on macOs and windows
// Initate auto-updates on MacOS and Windows
appUpdater();
}
});
checkConnection();
});
app.on('will-quit', () => {
// unregister all the shortcuts so that they don't interfare with other apps
// Unregister all the shortcuts so that they don't interfare with other apps
electronLocalshortcut.unregisterAll(mainWindow);
});
ipc.on('new-domain', (e, domain) => {
// mainWindow.loadURL(domain);
// MainWindow.loadURL(domain);
if (!mainWindow) {
mainWindow = createMainWindow();
mainWindow.loadURL(domain);
mainWindow.webContents.send('destroytray');
} else if (mainWindow.isMinimized()) {
mainWindow.webContents.send('destroytray');
mainWindow.loadURL(domain);
mainWindow.show();
} else {
mainWindow.webContents.send('destroytray');
mainWindow.loadURL(domain);
serverError(domain);
}
targetLink = domain;
});

View File

@@ -10,6 +10,7 @@ function linkIsInternal(currentUrl, newUrl) {
// We'll be needing this to open images in default browser
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
exports = module.exports = {
linkIsInternal, skipImages
module.exports = {
linkIsInternal,
skipImages
};

View File

@@ -2,10 +2,13 @@
const os = require('os');
const electron = require('electron');
const {dialog} = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const shell = electron.shell;
const appName = app.getName();
// Const tray = require('./tray');
const {addDomain, about} = require('./windowmanager');
@@ -19,12 +22,21 @@ function sendAction(action) {
win.webContents.send(action);
}
function clearCache() {
const win = BrowserWindow.getAllWindows()[0];
const ses = win.webContents.session;
ses.clearCache(() => {
dialog.showMessageBox({type: 'info', buttons: [], message: 'Cache cleared!'});
});
}
const viewSubmenu = [
{
label: 'Reload',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.reload();
focusedWindow.webContents.send('destroytray');
}
}
},
@@ -64,6 +76,14 @@ const viewSubmenu = [
{
type: 'separator'
},
{
label: 'Toggle Tray Icon',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.webContents.send('toggletray');
}
}
},
{
label: 'Toggle Developer Tools',
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
@@ -134,8 +154,15 @@ const darwinTpl = [
{
type: 'separator'
},
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{
label: 'Log Out',
accelerator: 'Cmd+L',
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('log-out');
@@ -263,8 +290,15 @@ const otherTpl = [
{
type: 'separator'
},
{
label: 'Clear Cache',
click() {
clearCache();
}
},
{
label: 'Log Out',
accelerator: 'Ctrl+L',
click(item, focusedWindow) {
if (focusedWindow) {
sendAction('log-out');
@@ -312,7 +346,6 @@ const otherTpl = [
{
role: 'selectall'
}
]
},
{

View File

@@ -1,22 +0,0 @@
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
// Implement spellcheck using electron api
window.spellCheckHandler = new SpellCheckHandler();
window.spellCheckHandler.attachToInput();
// Start off as US English
window.spellCheckHandler.switchLanguage('en-US');
const contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
const contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
// 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();
});

View File

@@ -1,61 +0,0 @@
'use strict';
const path = require('path');
const electron = require('electron');
const app = require('electron').app;
const {addDomain, about} = require('./windowmanager');
let tray = null;
const APP_ICON = path.join(__dirname, '../resources/tray', 'tray');
const iconPath = () => {
if (process.platform === 'linux') {
return APP_ICON + 'linux.png';
}
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
};
exports.create = () => {
const contextMenu = electron.Menu.buildFromTemplate([
{
label: 'About',
click() {
about();
}
},
{
type: 'separator'
},
{
label: 'Change Zulip server',
click() {
addDomain();
}
},
{
type: 'separator'
},
{
label: 'Reload',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.reload();
}
}
},
{
type: 'separator'
},
{
label: 'Quit',
click() {
app.quit();
}
}
]);
tray = new electron.Tray(iconPath());
tray.setToolTip(`${app.getName()}`);
tray.setContextMenu(contextMenu);
};

View File

@@ -1,12 +1,18 @@
'use strict';
const path = require('path');
const electron = require('electron');
const ipc = require('electron').ipcMain;
const APP_ICON = path.join(__dirname, '../resources', 'Icon');
const iconPath = () => {
return APP_ICON + (process.platform === 'win32' ? '.ico' : '.png');
};
let domainWindow;
let aboutWindow;
function onClosed() {
// dereference the window
// Dereference the window
domainWindow = null;
aboutWindow = null;
}
@@ -14,10 +20,14 @@ function onClosed() {
// Change Zulip server Window
function createdomainWindow() {
const domainwin = new electron.BrowserWindow({
title: 'Switch Server',
frame: false,
height: 300,
resizable: false,
width: 400
width: 400,
show: false,
icon: iconPath()
});
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
domainwin.loadURL(domainURL);
@@ -25,13 +35,20 @@ function createdomainWindow() {
return domainwin;
}
// Call this window onClick addDomain in tray
function addDomain() {
domainWindow = createdomainWindow();
domainWindow.show();
domainWindow.once('ready-to-show', () => {
domainWindow.show();
});
setTimeout(() => {
if (domainWindow !== null) {
if (!domainWindow.isDestroyed()) {
domainWindow.destroy();
}
}
}, 15000);
}
// About window
function createAboutWindow() {
const aboutwin = new electron.BrowserWindow({
@@ -48,7 +65,7 @@ function createAboutWindow() {
aboutwin.loadURL(aboutURL);
aboutwin.on('closed', onClosed);
// stop page to update it's title
// Stop page to update it's title
aboutwin.on('page-title-updated', e => {
e.preventDefault();
});
@@ -61,9 +78,23 @@ function createAboutWindow() {
// Call this onClick About in tray
function about() {
aboutWindow = createAboutWindow();
aboutWindow.show();
aboutWindow.once('ready-to-show', () => {
aboutWindow.show();
});
}
exports = module.exports = {
addDomain, about
ipc.on('trayabout', event => {
if (event) {
about();
}
});
ipc.on('traychangeserver', event => {
if (event) {
addDomain();
}
});
module.exports = {
addDomain,
about
};

View File

@@ -1,11 +1,11 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "0.5.3",
"version": "0.5.10",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"email":"<svnitakash@gmail.com>",
"copyright": "©2016 Kandra Labs, Inc.",
"email": "<svnitakash@gmail.com>",
"copyright": "©2017 Kandra Labs, Inc.",
"author": {
"name": "Akash Nimare",
"email": "svnitakash@gmail.com"
@@ -27,17 +27,16 @@
"InstantMessaging"
],
"dependencies": {
"electron-is-dev": "*",
"electron-squirrel-startup":"*",
"configstore": "^2.0.0",
"dialogs": "1.1.14",
"electron-context-menu": "0.4.0",
"electron-debug": "^1.0.0",
"electron-dl": "^0.2.0",
"electron-localshortcut": "^0.6.1",
"node-json-db": "^0.7.2",
"request": "^2.74.0",
"electron-spellchecker": "^0.5.12",
"wurl": "^2.1.0"
"electron-config":"0.2.1",
"electron-debug": "1.1.0",
"electron-is-dev": "0.1.2",
"electron-localshortcut": "1.0.0",
"electron-log": "1.3.0",
"electron-spellchecker": "1.0.5",
"electron-updater": "1.11.2",
"https": "^1.0.0",
"node-json-db": "0.7.3",
"request": "2.79.0",
"wurl": "2.1.0"
}
}

View File

@@ -6,17 +6,19 @@
</head>
<body>
<div class="about">
<center><img src="../resources/zulip.png"></center>
<center><p class="detail" id="version"> Version : ?.?.? </p>
<center><p class="detail"> License : Apache </p>
<center><p class="detail"> Maintainer : Zulip </p>
<p class="left"><a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a></p>
<img class="logo" src="../resources/zulip.png" />
<p class="detail" id="version">version ?.?.?</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>
</div>
</div>
<script>
const app = require('electron').remote.app;
const version_tag = document.getElementById('version');
version_tag.innerHTML = ' Version : ' + app.getVersion() + ' ';
version_tag.innerHTML = 'version ' + app.getVersion();
function linkInBrowser(event) {

View File

@@ -1,15 +1,22 @@
body {
background: #6BB6C7;
background: #fafafa;
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
}
.logo {
display: block;
margin: 0 auto;
}
#version {
color: #aaa;
font-size: 0.9em;
}
.about {
margin-top: 50px;
}
.left {
position: absolute;
top:89%;
left:76%;
text-align: center;
}
.about p {
@@ -18,10 +25,49 @@ body {
}
.about img {
width:160px;
width: 150px;
}
.detail {
text-align: left;
margin-left: 35%;
}
text-align: center;
}
.detail.maintainer {
font-size: 1.2em;
font-weight: 500;
}
.detail.license {
font-size: 0.8em;
}
.maintenance-info {
position: absolute;
width: 100%;
bottom: 20px;
left: 0px;
color: #444;
}
.maintenance-info p {
margin: 0;
font-size: 1em;
width: 100%;
}
.maintenance-info .bug {
display: inline-block;
padding: 8px 15px;
margin-top: 30px;
text-decoration: none;
background-color: #52c2af;
color: #fff;
border-radius: 4px;
transition: background-color 0.2s ease;
}
.maintenance-info .bug:hover {
background-color: #32a692;
}

View File

@@ -1,375 +1,143 @@
@charset "UTF-8";
header,
section {
display: block
* {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
Helvetica, Arial, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol";
-webkit-font-smoothing: antialiased;
color: #444;
vertical-align: top;
}
html {
font-size: 100%;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
}
html,
button,
input {
font-family: "Helvetica Neue", Arial, sans-serif
}
html,
body {
height: 100%;
margin: 0
}
img {
border: 0;
-ms-interpolation-mode: bicubic
}
img {
vertical-align: middle
}
form {
margin: 0
}
fieldset {
border: 0;
margin: 0;
padding: 0
}
button,
input {
font-size: 100%;
margin: 0;
vertical-align: baseline;
box-sizing: content-box;
-webkit-box-sizing: content-box
}
button,
input {
line-height: normal
background-image: url(../img/topography.png);
}
input,
button {
cursor: pointer;
-webkit-appearance: button;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0
}
hr {
display: none
}
img {
max-width: 100%
}
h1 {
color: #111;
line-height: 1em;
font-weight: 400;
font-family: "Helvetica Neue", Arial, sans-serif;
text-rendering: optimizelegibility;
-webkit-text-stroke: none
}
h1 {
margin: 0 0 35px
font-size: 1em;
}
body.container-layout header #logo {
position: relative;
display: inline-block;
vertical-align: top
}
body.container-layout header #logo {
width: 50px;
height: 50px;
background-position: -790px 0
}
button[type=submit] {
text-decoration: none;
display: inline-block;
vertical-align: top;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 4px;
border-radius: 4px;
position: relative;
font-family: "Helvetica Neue", Arial, sans-serif;
font-size-adjust: auto;
vertical-align: bottom;
background-color: #e6eaef;
border: 2px solid #e6eaef;
color: #96a0ac;
font-size: 20px;
line-height: 26px;
padding: 6px 17px
}
.desktop button[type=submit] {
-webkit-transition: all .2s ease-in-out;
transition: all .2s ease-in-out
}
.desktop button[type=submit]:hover {
background-color: #eff2f5;
border: 2px solid #eff2f5;
color: #96a0ac
}
button[type=submit]:focus {
outline: 0
}
button[type=submit].btn-primary {
background-color: #20b36c;
border: 2px solid #20b36c;
color: #fff
}
.desktop button[type=submit].btn-primary:hover {
background-color: #39ca83;
border: 2px solid #39ca83;
color: #fff
}
button[type=submit].btn-primary:focus {
outline: 0
}
button[type=submit].btn-large {
font-family: "Helvetica Neue", Arial, sans-serif;
font-size: 20px;
line-height: 26px;
padding: 12px 30px
}
input[type=text] {
font-family: "Helvetica Neue", Arial, sans-serif;
font-weight: 200;
display: inline-block;
vertical-align: top;
-webkit-border-radius: 4px;
border-radius: 4px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-color: #fff;
border: 1px solid #cad0d7;
color: #000;
font-size: 18px;
line-height: 26px;
height: 42px;
padding: 10px 10px
}
.desktop input[type=text]:hover {
background-color: #fff;
border-color: #bbc3cc;
color: #111
}
input[type=text]:focus {
background-color: #fff;
border-color: #20b36c!important;
color: #000;
outline: 0
}
input[type=text]::-webkit-input-placeholder {
color: #8e959e
}
input[type=text]::-moz-placeholder {
color: #8e959e
}
input[type=text]:-ms-input-placeholder {
color: #8e959e
}
.form-large input[type=text] {
font-size: 18px;
line-height: 26px;
height: 54px;
padding: 12px 15px
}
.control-group {
margin-top: 40px
}
h1 {
white-space: normal;
word-break: break-all;
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto
}
.section-main {
position: relative
}
body {
color: #111;
font-size: 18px;
line-height: 24px;
font-family: "Helvetica Neue", Arial, sans-serif;
background: #edf1f3;
-webkit-box-sizing: border-box;
box-sizing: border-box
}
.desktop body {
padding-top: 116px
}
body.container-layout {
padding: 0!important;
background-color: #E6EAEF
}
header {
z-index: 800;
border-bottom: 1px solid #dae0e7;
background: rgba(255, 255, 255, .97);
-webkit-box-sizing: border-box;
box-sizing: border-box;
position: relative;
top: 0;
left: 0;
width: 100%
}
header .container {
position: relative
}
.desktop header {
position: fixed
}
header .container {
position: relative;
height: 75px
}
.container-layout header {
position: relative;
border: 0;
background: 0 0;
padding: 30px 0
}
.container-layout header .container {
height: auto
}
header #logo {
display: block;
text-indent: -9999px
text-align: center;
margin: 0px 0px 30px 0px;
}
header #logo {
position: absolute!important;
top: 50%;
left: 10px;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%)
header img {
width: 50px;
}
body.container-layout header #logo {
position: relative!important;
top: 0;
left: 0;
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
margin: 0 auto;
display: block
header h1 {
display: inline-block;
margin: 10px 0px 10px 10px;
font-weight: 500;
}
.content {
padding-bottom: 40px;
overflow: hidden
section.server {
display: inline-block;
padding: 50px;
margin-top: calc(50vh - 135px);
text-align: left;
box-shadow: 0px 0px 100px rgba(0,0,0,0.15);
background-color: #fff;
animation-name: pulse;
animation-duration: 2s;
animation-iteration-count: infinite;
}
.container-layout .content {
max-width: 660px;
margin: 0 auto
section.shake {
animation-name: shake;
animation-duration: 0.5s;
animation-iteration-count: 1;
}
.content .server {
position: relative;
margin: 0 10px
form label {
display: block;
font-weight: 600;
margin-bottom: 5px;
}
.content .server .container {
background: #fff;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 50px 0 0;
-webkit-border-radius: 4px;
border-radius: 4px;
position: relative;
z-index: 10;
max-width: 580px
form input[type=text] {
width: 300px;
border: 2px solid #ccc;
padding: 10px 10px;
outline: none;
transition: all 0.2s ease;
}
.content .server h1 {
form input[type=text]:hover,
form input[type=text]:focus {
border-color: #aaa;
}
form button {
padding: 10px 10px;
background-color: #52c2af;
color: #fff;
border: 2px solid #52c2af;
outline: none;
cursor: pointer;
transition: all 0.2s ease;
}
form button:hover {
background-color: #30b09a;
border-color: #30b09a;
}
form button:active {
background-color: #14957f;
border-color: #14957f;
}
form #error {
margin: 5px 0px 0px;
font-size: 0.8em;
font-weight: 600;
color: rgb(201, 107, 107);
opacity: 0;
transform: translateY(-10px);
height: 15px;
transition: all 0.2s ease;
}
form #error.show {
opacity: 1;
transform: translateY(0px);
}
/* -- generic components -- */
.center {
text-align: center;
padding: 0 10%
}
.content .server h1 {
font-size: 2.4em;
line-height: 1.2em;
margin-bottom: 10px
@keyframes pulse {
0% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
50% { box-shadow: 0px 0px 100px rgba(0,0,0,0.30); }
100% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
}
.content .server fieldset {
padding: 25px 10% 80px 39px;
position: relative
}
.content .server fieldset .control-group .control-field input {
width: 100%
}
.content .server button {
width: 100%
}
@media screen and (min-width: 749px) {
input[type=text] {
width: 60%
}
}
@media screen and (min-width: 1071px) {
h1 {
font-size: 3.2em;
line-height: 1.3em
}
}
.container {
width: 1070px;
margin-left: auto;
margin-right: auto;
padding-left: 10px;
padding-right: 10px;
}
.container:before,
.container:after {
content: "";
display: table
}
.container:after {
clear: both
}
.responsive .container {
max-width: 1070px;
width: auto;
margin-left: auto;
margin-right: auto;
padding-left: 10px;
padding-right: 10px;
}
.responsive .container:before,
.responsive .container:after {
content: "";
display: table
}
.responsive .container:after {
clear: both
}
@media screen and (max-width: 480px) {
.responsive h1 {
font-size: 1.7em;
line-height: 1.3em
}
}
@media screen and (min-width: 481px) and (max-width: 640px) {
.responsive h1 {
font-size: 1.9em;
line-height: 1.3em
}
}
@media screen and (min-width: 641px) and (max-width: 748px) {
.responsive h1 {
font-size: 2.2em;
line-height: 1.3em
}
}
@media screen and (max-width: 748px) {
.responsive input[type=text] {
width: 100%
}
}
@media screen and (min-width: 749px) and (max-width: 1070px) {
.responsive h1 {
font-size: 2.6em;
line-height: 1.3em
}
}
#server-status {
text-align: center;
color: #c71212;
@keyframes shake {
10%, 90% { transform: translate3d(-1px, 0, 0); }
20%, 80% { transform: translate3d(2px, 0, 0); }
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
40%, 60% { transform: translate3d(4px, 0, 0); }
}

View File

@@ -71,13 +71,4 @@ button:focus {
top: -61%;
left: 25%;
text-align: center;
}
#pic {
width: 20px;
left: 36%;
margin-left: 4px;
top: 63%;
display: none;
position: absolute;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -7,36 +7,24 @@
<title>Login - Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head>
<body class="container-layout">
<div class="section-main">
<header>
<div class="container">
<img src="../resources/zulip.png" id="logo"/>
<body>
<div class="center">
<section class="server">
<header>
<img src="../resources/zulip.png" id="logo"/>
<h1>Zulip Login</h1>
</header>
<div class="container">
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
<label for="url">
Zulip Server URL
</label>
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="Server URL">
<button type="submit" id="main" class="btn-primary btn-large" value="Submit">Connect</button>
<p id="error"></p>
</form>
</div>
</section>
</div>
</header>
<hr>
<section class="content">
<section class="server">
<div class="container">
<h1>Login to Zulip Server</h1>
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
<fieldset>
<div class="control-group control-required">
<div class="control-field">
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="chat.zulip.org">
</div>
</div>
<div class="control-group">
<div class="control-submit">
<button type="submit" id="main" class="btn-primary btn-large" value="Submit" onclick="addDomain();">Connect</button>
</div>
</div>
<p id="server-status"><p>
</fieldset>
</form>
</div>
</section>
</section>
</div>
</body>
</body>
</html>

80
app/renderer/js/domain.js Normal file
View File

@@ -0,0 +1,80 @@
const {app} = require('electron').remote;
const ipcRenderer = require('electron').ipcRenderer;
const JsonDB = require('node-json-db');
const request = require('request');
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
window.addDomain = function () {
const el = sel => {
return document.querySelector(sel);
};
const $el = {
error: el('#error'),
main: el('#main'),
section: el('section')
};
const event = sel => {
return {
on: (event, callback) => {
document.querySelector(sel).addEventListener(event, callback);
}
};
};
const displayError = msg => {
$el.error.innerText = msg;
$el.error.classList.add('show');
$el.section.classList.add('shake');
};
let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, '');
if (newDomain === '') {
displayError('Please input a valid URL.');
} else {
el('#main').innerHTML = 'Checking...';
if (newDomain.indexOf('localhost:') >= 0) {
const domain = 'http://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
$el.main.innerHTML = 'Connect';
displayError('Not a valid Zulip local server');
}
});
// });
} else {
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
$el.main.innerHTML = 'Connect';
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
$el.main.innerHTML = 'Connect';
ipcRenderer.send('certificate-err', domain);
} else {
$el.main.innerHTML = 'Connect';
displayError('Not a valid Zulip server');
}
});
}
}
event('#url').on('input', () => {
el('#error').classList.remove('show');
});
event('section').on('animationend', function () {
this.classList.remove('shake');
});
};

View File

@@ -14,7 +14,7 @@ document.addEventListener('keydown', event => {
}
});
// eslint-disable-next-line no-unused-vars
function addDomain() {
window.prefDomain = function () {
const request = require('request');
// eslint-disable-next-line import/no-extraneous-dependencies
const ipcRenderer = require('electron').ipcRenderer;
@@ -23,26 +23,47 @@ function addDomain() {
const {app} = require('electron').remote;
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
document.getElementById('main').innerHTML = 'checking...';
document.getElementById('pic').style.display = 'block';
let newDomain = document.getElementById('url').value;
newDomain = newDomain.replace(/^https?:\/\//, '');
newDomain = newDomain.replace(/^http?:\/\//, '');
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
if (newDomain === '') {
document.getElementById('urladded').innerHTML = 'Please input a value';
} else {
document.getElementById('main').innerHTML = 'Checking...';
if (newDomain.indexOf('localhost:') >= 0) {
const domain = 'http://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a valid Zulip Local Server.';
}
});
} else {
document.getElementById('pic').style.display = 'none';
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a vaild Zulip Server.';
const domain = 'https://' + newDomain;
const checkDomain = domain + '/static/audio/zulip.ogg';
request(checkDomain, (error, response) => {
if (!error && response.statusCode !== 404) {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
db.push('/domain', domain);
ipcRenderer.send('new-domain', domain);
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
document.getElementById('main').innerHTML = 'Switch';
ipcRenderer.send('certificate-err', domain);
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
} else {
document.getElementById('main').innerHTML = 'Switch';
document.getElementById('urladded').innerHTML = 'Not a valid Zulip Server.';
}
});
}
});
}
}
};

View File

@@ -1,8 +1,22 @@
'use strict';
const ipcRenderer = require('electron').ipcRenderer;
const {webFrame} = require('electron');
// Handle zooming functionality
const {spellChecker} = require('./spellchecker');
const _setImmediate = setImmediate;
const _clearImmediate = clearImmediate;
process.once('loaded', () => {
global.setImmediate = _setImmediate;
global.clearImmediate = _clearImmediate;
});
// eslint-disable-next-line import/no-unassigned-import
require('./domain');
// eslint-disable-next-line import/no-unassigned-import
require('./tray.js');
// Calling Tray.js in renderer process everytime app window loads
// Handle zooming functionality
const zoomIn = () => {
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
};
@@ -29,7 +43,7 @@ ipcRenderer.on('zoomActualSize', () => {
});
ipcRenderer.on('log-out', () => {
// create the menu for the below
// Create the menu for the below
document.querySelector('.dropdown-toggle').click();
const nodes = document.querySelectorAll('.dropdown-menu li:last-child a');
@@ -37,16 +51,19 @@ ipcRenderer.on('log-out', () => {
});
ipcRenderer.on('shortcut', () => {
// create the menu for the below
document.querySelector('.dropdown-toggle').click();
const nodes = document.querySelectorAll('.dropdown-menu li:nth-child(4) a');
nodes[nodes.length - 1].click();
// Create the menu for the below
const node = document.querySelector('a[data-overlay-trigger=keyboard-shortcuts]');
// Additional check
if (node.text.trim().toLowerCase() === 'keyboard shortcuts') {
node.click();
} else {
// Atleast click the dropdown
document.querySelector('.dropdown-toggle').click();
}
});
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
require('./spellchecker')();
// Init spellchecker
spellChecker();
});
require('./domain')();

View File

@@ -0,0 +1,27 @@
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
function spellChecker() {
// Implement spellcheck using electron api
window.spellCheckHandler = new SpellCheckHandler();
window.spellCheckHandler.attachToInput();
// Start off as US English
window.spellCheckHandler.switchLanguage('en-US');
const contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
const contextMenuListener = new ContextMenuListener(info => {
contextMenuBuilder.showPopupMenu(info);
});
// 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();
});
}
module.exports = {
spellChecker
};

188
app/renderer/js/tray.js Normal file
View File

@@ -0,0 +1,188 @@
'use strict';
const path = require('path');
const electron = require('electron');
const {ipcRenderer, remote} = electron;
const {Tray, Menu, nativeImage} = remote;
const APP_ICON = path.join(__dirname, '../../resources/tray', 'tray');
const iconPath = () => {
if (process.platform === 'linux') {
return APP_ICON + 'linux.png';
}
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
};
let unread = 0;
const trayIconSize = () => {
switch (process.platform) {
case 'darwin':
return 20;
case 'win32':
return 100;
case 'linux':
return 100;
default: return 80;
}
};
// Default config for Icon we might make it OS specific if needed like the size
const config = {
pixelRatio: window.devicePixelRatio,
unreadCount: 0,
showUnreadCount: true,
unreadColor: '#000000',
readColor: '#000000',
unreadBackgroundColor: '#B9FEEA',
readBackgroundColor: '#B9FEEA',
size: trayIconSize(),
thick: process.platform === 'win32'
};
const renderCanvas = function (arg) {
config.unreadCount = arg;
return new Promise((resolve, reject) => {
const SIZE = config.size * config.pixelRatio;
const PADDING = SIZE * 0.05;
const CENTER = SIZE / 2;
const HAS_COUNT = config.showUnreadCount && config.unreadCount;
const color = config.unreadCount ? config.unreadColor : config.readColor;
const backgroundColor = config.unreadCount ? config.unreadBackgroundColor : config.readBackgroundColor;
const canvas = document.createElement('canvas');
canvas.width = SIZE;
canvas.height = SIZE;
const ctx = canvas.getContext('2d');
// Circle
// If (!config.thick || config.thick && HAS_COUNT) {
ctx.beginPath();
ctx.arc(CENTER, CENTER, (SIZE / 2) - PADDING, 0, 2 * Math.PI, false);
ctx.fillStyle = backgroundColor;
ctx.fill();
ctx.lineWidth = SIZE / (config.thick ? 10 : 20);
ctx.strokeStyle = backgroundColor;
ctx.stroke();
// Count or Icon
if (HAS_COUNT) {
ctx.fillStyle = color;
ctx.textAlign = 'center';
if (config.unreadCount > 99) {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.4}px Helvetica`;
ctx.fillText('99+', CENTER, CENTER + (SIZE * 0.15));
} else if (config.unreadCount < 10) {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.20));
} else {
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.15));
}
resolve(canvas);
} else {
reject(canvas);
}
});
};
/**
* Renders the tray icon as a native image
* @param arg: Unread count
* @return the native image
*/
const renderNativeImage = function (arg) {
return Promise.resolve()
.then(() => renderCanvas(arg))
.then(canvas => {
const pngData = nativeImage.createFromDataURL(canvas.toDataURL('image/png')).toPng();
return Promise.resolve(nativeImage.createFromBuffer(pngData, config.pixelRatio));
});
};
const createTray = function () {
window.tray = new Tray(iconPath());
const contextMenu = Menu.buildFromTemplate([{
label: 'About',
click() {
ipcRenderer.send('trayabout');
}
},
{
type: 'separator'
},
{
label: 'Change Zulip server',
click() {
ipcRenderer.send('traychangeserver');
}
},
{
type: 'separator'
},
{
label: 'Reload',
click() {
remote.getCurrentWindow().reload();
window.tray.destroy();
}
},
{
type: 'separator'
},
{
label: 'Quit',
click() {
remote.getCurrentWindow().close();
}
}
]);
window.tray.setContextMenu(contextMenu);
};
ipcRenderer.on('destroytray', event => {
window.tray.destroy();
if (window.tray.isDestroyed()) {
window.tray = null;
} else {
throw new Error('Tray icon not properly destroyed.');
}
return event;
});
ipcRenderer.on('tray', (event, arg) => {
if (arg === 0) {
unread = arg;
// Message Count // console.log("message count is zero.");
window.tray.setImage(iconPath());
window.tray.setToolTip('No unread messages');
} else {
unread = arg;
renderNativeImage(arg).then(image => {
window.tray.setImage(image);
window.tray.setToolTip(arg + ' unread messages');
});
}
});
ipcRenderer.on('toggletray', event => {
if (event) {
if (window.tray) {
window.tray.destroy();
if (window.tray.isDestroyed()) {
window.tray = null;
}
} else {
createTray();
renderNativeImage(unread).then(image => {
window.tray.setImage(image);
window.tray.setToolTip(unread + ' unread messages');
});
}
}
});
createTray();

View File

@@ -3,17 +3,14 @@
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/pref.css">
<script type="text/javascript">
</script>
</head>
<body>
<div class="close" id="close-button">Close</div>
<div class="form">
<form onsubmit="addDomain(); return false">
<input id="url" type="text" placeholder="chat.zulip.org">
<button type="submit" id="main" value="Submit" onclick="addDomain();">
<form onsubmit="prefDomain(); return false">
<input id="url" type="text" placeholder="Server URL">
<button type="submit" id="main" value="Submit">
Switch</button>
<img id="pic" src="img/loader.gif" />
</form>
<p id="urladded"><p>
</div>

View File

@@ -1,11 +1,12 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "0.5.3",
"version": "0.5.10",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"email":"<svnitakash@gmail.com>",
"copyright": "©2016 Kandra Labs, Inc.",
"email": "<svnitakash@gmail.com>",
"copyright": "©2017 Kandra Labs, Inc.",
"author": {
"name": "Akash Nimare",
"email": "svnitakash@gmail.com"
@@ -24,30 +25,33 @@
"dev": "gulp dev",
"pack": "build --dir",
"dist": "build",
"build:win": "build --win nsis-web --ia32 --x64",
"travis": "cd ./scripts && ./travis-build-test.sh"
},
"build": {
"appId": "org.zulip.zulip-electron",
"asar": "true",
"asar": true,
"files": [
"**/*",
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
],
"copyright": "©2016 Kandra Labs, Inc.",
"copyright": "©2017 Kandra Labs, Inc.",
"mac": {
"category": "public.app-category.productivity"
},
"linux" : {
"synopsis": "Zulip Desktop App",
"linux": {
"category": "",
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
"description": "Zulip Desktop Client for Linux",
"target" : ["deb", "AppImage"],
"version" : "0.5.3",
"title" : "Zulip",
"license": "Apache-2.0",
"target": [
"deb",
"AppImage"
],
"maintainer": "Akash Nimare <svnitakash@gmail.com>"
},
"deb": {
"synopsis": "Zulip Desktop App"
},
"dmg": {
"background": "build/appdmg.png",
"icon": "build/icon.icns",
@@ -67,28 +71,32 @@
]
},
"win": {
"target": "squirrel",
"target": "nsis",
"icon": "build/icon.ico"
},
"nsis": {
"perMachine": true,
"oneClick": false
}
},
"keywords": [
"Zulip",
"Group Chat app",
"electron-app",
"electron",
"Desktop app",
"InstantMessaging"
"Zulip",
"Group Chat app",
"electron-app",
"electron",
"Desktop app",
"InstantMessaging"
],
"devDependencies": {
"assert": "^1.4.1",
"devtron": "^1.1.0",
"electron-builder": "*",
"electron": "1.4.7",
"electron-connect": "^0.4.6",
"gulp": "^3.9.1",
"gulp-mocha": "^3.0.1",
"spectron": "^3.3.0",
"xo": "*"
"assert": "1.4.1",
"devtron": "1.4.0",
"electron-builder": "16.6.0",
"electron": "1.4.15",
"electron-connect": "0.4.8",
"gulp": "3.9.1",
"gulp-mocha": "3.0.1",
"spectron": "3.6.1",
"xo": "0.18.1"
},
"xo": {
"esnext": true,
@@ -98,12 +106,13 @@
"rules": {
"max-lines": [
"warn",
350
500
],
"no-warning-comments": 0,
"capitalized-comments": 0,
"no-else-return": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies":0
"import/no-extraneous-dependencies": 0
}
}
],

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env bash
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
export DISPLAY=:99.0
export {no_proxy,NO_PROXY}="127.0.0.1,localhost"
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
sleep 3
fi

View File

@@ -7,7 +7,7 @@ describe('application launch', function () {
beforeEach(function () {
this.app = new Application({
path: require('electron'),
args: [__dirname + '/../app/main/index.js']
args: [__dirname + '/../app/renderer/index.html']
})
return this.app.start()
})

View File

@@ -74,11 +74,11 @@ gitCheckout()
}
# }}}
# {{{ npmUpgradeStart()
# {{{ npmInstallStart()
npmUpgradeStart()
npmInstallStart()
{
npm upgrade
npm install
npm start &
}
@@ -105,5 +105,5 @@ cleanUp()
envSetup $*
gitCheckout
npmUpgradeStart
cleanUp
npmInstallStart
cleanUp