Compare commits

...

17 Commits

Author SHA1 Message Date
Akash Nimare
3eec4c2209 release: 🎉 new release v2.3.6. 2018-08-23 20:10:18 +05:30
Akash Nimare
debbfb6b7d electron: Update electron to v2.0.8. 2018-08-23 18:56:36 +05:30
Akash Nimare
8bd1492586 left-sidebar: Do not escape realm name.
We escape the realm name whenever user adds a realm + on app startup.
That's why we don't need to do the double escaping for already added
servers.

Fixes: #541.
2018-08-23 18:48:06 +05:30
Akash Nimare
1115c6d5c3 docs: Remove help docs from the repo.
Content is now maintained in the /help docs.

Fixes: #543.
2018-08-23 12:32:25 +05:30
Abhigyan Khaund
9ba279213c proxy: Add proxy details in request module parameters.
This commit adds proxy details to request module paramters from
the proxyRules so that the request module can use these rules while
sending a request. In case of no system proxy, set environment
variable NO_PROXY to handle all links.

Fixes: #534.
2018-08-21 00:26:37 +05:30
Akash Nimare
89c35cb1d4 electron: Update electron to v2.0.7. 2018-08-17 14:16:00 +05:30
Akash Nimare
21d6eb52c5 sentry: Update Sentry to v0.8.1.
This fixes the youtube video not playing in the lightbox issue.
Youtube video stopped playing in the lightbox when we added the
Sentry support. The exact reason behind the issue is still unknown
but we're guessing that previous version of Sentry doesn't exit
process on oncaught errors which might have caused lightbox to break.
The issue was fixed in the latest release of the Sentry v0.8.1.

Fixes: #537.
2018-08-14 18:02:10 +05:30
Akash Nimare
aa1538837b Add v2.3.5 release notes. 2018-08-03 17:39:48 +05:30
Akash Nimare
ea103380b6 release: 🎉 new release v2.3.5. 2018-08-02 20:27:29 +05:30
aashish-ak
60d10d88d1 preload: use page_params only when it exists.
This PR adds a params-util.js file which checks wheather the
page_params exists or not.

Fixes: #517.
2018-08-02 20:00:42 +05:30
Abhigyan Khaund
124a842bbd electron-bridge: Implement electron bridge.
This PR adds a bridge to communicate with the webapp in real time. As of now, the bridge listens for following events -

* When realm name changes
* When realm icon changes
* When the unread count changes

Partially fixes #425.
2018-08-02 01:05:29 +05:30
Akash Nimare
7130103999 file-attachment: Update notification message. 2018-08-02 00:11:47 +05:30
Akash Nimare
26a144e1c2 Merge branch 'master' of github.com:zulip/zulip-electron 2018-08-01 23:50:21 +05:30
Akash Nimare
a5c1ae8726 file-attachment: Add a setting option to show downloaded file in file manager. 2018-08-01 23:50:02 +05:30
Abhigyan Khaund
ed5096840d attachments: Fix failing attached file downloads.
This commit fixes the failing download files that had occurred due to the session not being the same in the browserWindow and the webview. This made the uploaded files unavailable to browserWindow for download. This fix adds the persist session to the browserWindow.

Fixes: #523.
2018-07-31 19:38:39 +05:30
Abhigyan Khaund
3f6d256910 gulpfile: Update syntax and methods for gulp v4.x.
This fixes the broken e2e-test.
2018-07-25 16:14:04 +05:30
Akash Nimare
28421992ba Update changelog.md 2018-07-24 19:31:25 +05:30
20 changed files with 524 additions and 241 deletions

View File

@@ -73,7 +73,8 @@ function createMainWindow() {
minHeight: 400,
webPreferences: {
plugins: true,
nodeIntegration: true
nodeIntegration: true,
partition: 'persist:webviewsession'
},
show: false
});
@@ -175,7 +176,7 @@ app.on('ready', () => {
});
page.once('did-frame-finish-load', () => {
// Initate auto-updates on MacOS and Windows
// Initiate auto-updates on MacOS and Windows
if (ConfigUtil.getConfigItem('autoUpdate')) {
appUpdater();
}
@@ -278,6 +279,10 @@ app.on('ready', () => {
});
});
});
ipcMain.on('realm-icon-changed', (event, serverURL, iconURL) => {
page.send('update-realm-icon', serverURL, iconURL);
});
});
app.on('before-quit', () => {

View File

@@ -4,6 +4,7 @@ const { Notification } = require('electron');
const request = require('request');
const semver = require('semver');
const ConfigUtil = require('../renderer/js/utils/config-util');
const ProxyUtil = require('../renderer/js/utils/proxy-util');
const LinuxUpdateUtil = require('../renderer/js/utils/linux-update-util');
const Logger = require('../renderer/js/utils/logger-util');
@@ -15,10 +16,12 @@ const logger = new Logger({
function linuxUpdateNotification() {
let url = 'https://api.github.com/repos/zulip/zulip-electron/releases';
url = ConfigUtil.getConfigItem('betaUpdate') ? url : url + '/latest';
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
const options = {
url,
headers: {'User-Agent': 'request'}
headers: {'User-Agent': 'request'},
proxy: proxyEnabled ? ProxyUtil.getProxy(url) : ''
};
request(options, (error, response, body) => {

139
app/package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "zulip",
"version": "2.3.4-beta",
"version": "2.3.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -37,56 +37,91 @@
}
},
"@sentry/browser": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-0.5.4.tgz",
"integrity": "sha1-Yh/5chgrc7YoVlhLkvxl/elpBMw=",
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.0.0-beta.12.tgz",
"integrity": "sha512-At8qp2aM4q4KnuIQuC6wbbQ6gLykmzwZdHwWRN99GS5TNC7kXJNgO9WgiMLadA4ph12JtC1petrUIgY8t+aoSA==",
"requires": {
"@sentry/core": "0.5.4",
"@sentry/shim": "0.5.4"
"@sentry/core": "4.0.0-beta.12",
"@sentry/hub": "4.0.0-beta.12",
"@sentry/minimal": "4.0.0-beta.12",
"@sentry/types": "4.0.0-beta.12",
"@sentry/utils": "4.0.0-beta.12"
}
},
"@sentry/core": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-0.5.4.tgz",
"integrity": "sha1-mwqEK0QhMbOAG65wviyk6cUQV04=",
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.0.0-beta.12.tgz",
"integrity": "sha512-DGZqBOHejHPYP2I0MdF7APEaews7gLrfxHDh9rbwDLJJiuwPE/ridH97amxy/j2g4X4EZEc3sO3Ptv4nMaHK+Q==",
"requires": {
"@sentry/shim": "0.5.4"
"@sentry/hub": "4.0.0-beta.12",
"@sentry/minimal": "4.0.0-beta.12",
"@sentry/types": "4.0.0-beta.12",
"@sentry/utils": "4.0.0-beta.12"
}
},
"@sentry/electron": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@sentry/electron/-/electron-0.5.5.tgz",
"integrity": "sha1-kInWNC22xr1sCSpTdHcIAx1ft8M=",
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@sentry/electron/-/electron-0.8.1.tgz",
"integrity": "sha512-y3CJ7547Rhpg+6bnGP0mXLj9pgpjMLaRji704TdzTV0afr8KamBXySNhNHosHLaKm1OLg6p8U4pdVB7xQZ+X3g==",
"requires": {
"@sentry/browser": "0.5.4",
"@sentry/core": "0.5.4",
"@sentry/node": "0.5.4",
"@sentry/shim": "0.5.4",
"@sentry/utils": "0.5.4",
"@sentry/browser": "4.0.0-beta.12",
"@sentry/core": "4.0.0-beta.12",
"@sentry/hub": "4.0.0-beta.12",
"@sentry/minimal": "4.0.0-beta.12",
"@sentry/node": "4.0.0-beta.12",
"@sentry/types": "4.0.0-beta.12",
"@sentry/utils": "4.0.0-beta.12",
"electron-fetch": "^1.1.0",
"form-data": "^2.3.2",
"util.promisify": "^1.0.0"
}
},
"@sentry/node": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-0.5.4.tgz",
"integrity": "sha1-s+c0nRs2EjmVkDbqrhnOvzVkw9M=",
"@sentry/hub": {
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.0.0-beta.12.tgz",
"integrity": "sha512-fmLaPaD6F/ViWDTz3hRVnNvqgnAmX0foDsUGVVp0Dt2lT9apM5NECKV6761XFVMrbGGulCg9fguv2KV5IbQcIw==",
"requires": {
"@sentry/core": "0.5.4",
"@sentry/shim": "0.5.4",
"raven": "^2.6.0"
"@sentry/types": "4.0.0-beta.12",
"@sentry/utils": "4.0.0-beta.12"
}
},
"@sentry/shim": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@sentry/shim/-/shim-0.5.4.tgz",
"integrity": "sha1-y4JrGjR2WuXhsh5h3y3vL42pHcE="
"@sentry/minimal": {
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.0.0-beta.12.tgz",
"integrity": "sha512-1V3Lrm7wIOOqG+l1uyVZ7iQysPGXszwfsd6DTVDPT19PSey7+KbvPNcQfh+GqMRMz8jzyg9XlwUxckg7qbSztQ==",
"requires": {
"@sentry/hub": "4.0.0-beta.12",
"@sentry/types": "4.0.0-beta.12"
}
},
"@sentry/node": {
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-4.0.0-beta.12.tgz",
"integrity": "sha512-oekXtdaaElt/lSfyKtAyTLcTofciMRuptsGOTMX4qQ7hoHESB6DUw55Or/RRMaJYm/nckM2VFzWDATd20NVV4w==",
"requires": {
"@sentry/core": "4.0.0-beta.12",
"@sentry/hub": "4.0.0-beta.12",
"@sentry/minimal": "4.0.0-beta.12",
"@sentry/types": "4.0.0-beta.12",
"@sentry/utils": "4.0.0-beta.12",
"cookie": "0.3.1",
"lsmod": "1.0.0",
"md5": "2.2.1",
"stack-trace": "0.0.10"
}
},
"@sentry/types": {
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.0.0-beta.12.tgz",
"integrity": "sha512-xRsTfRcb8OvMbLjl64bPNv3feHiXBprtRZqTlVUbDJmSNrm8wg+tKIPYsP90dxKc50CZBk59urIbgvpPg0mCLw=="
},
"@sentry/utils": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-0.5.4.tgz",
"integrity": "sha1-jt54rOlgIW3WMv1WHIP1AGLlruE="
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.0.0-beta.12.tgz",
"integrity": "sha512-lpTE2GlaztATlFfIWMN8RSQFP0z6PkPPoDz0KKRmK4ZxjPxVX2sAGbKJGCpf9fdUG23NVg3FNiqfpUbjhvd9YA==",
"requires": {
"@sentry/types": "4.0.0-beta.12"
}
},
"@sindresorhus/is": {
"version": "0.7.0",
@@ -437,9 +472,9 @@
}
},
"electron-fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.1.0.tgz",
"integrity": "sha512-eBtqbB522c/RJwC5v1yF/Y0SMVLiwel98BWGx050GucWbKlejHtPkfpq/vfMxCjg0SGpHGUISYUaMfu65QH+xg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.2.1.tgz",
"integrity": "sha512-pQy0el/vxu30sL9JjXss8yZL+ztRnmioffPQsLL4UYnfSUFTuGBlgCPCxxKYJV7y52WfaIEZQ9tlbac1YHrH0w==",
"requires": {
"encoding": "^0.1.12"
}
@@ -538,9 +573,9 @@
}
},
"es-abstract": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
"integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz",
"integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==",
"requires": {
"es-to-primitive": "^1.1.1",
"function-bind": "^1.1.1",
@@ -829,9 +864,9 @@
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-callable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
"integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI="
},
"is-date-object": {
"version": "1.0.1",
@@ -1024,6 +1059,11 @@
"yallist": "^2.1.2"
}
},
"lsmod": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lsmod/-/lsmod-1.0.0.tgz",
"integrity": "sha1-mgD3bco26yP6BTUK/htYXUKZ5ks="
},
"md5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
@@ -1309,18 +1349,6 @@
"strict-uri-encode": "^1.0.0"
}
},
"raven": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/raven/-/raven-2.6.3.tgz",
"integrity": "sha512-bKre7qlDW+y1+G2bUtCuntdDYc8o5v1T233t0vmJfbj8ttGOgLrGRlYB8saelVMW9KUAJNLrhFkAKOwFWFJonw==",
"requires": {
"cookie": "0.3.1",
"md5": "^2.2.1",
"stack-trace": "0.0.10",
"timed-out": "4.0.1",
"uuid": "3.0.0"
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
@@ -1600,11 +1628,6 @@
"object.getownpropertydescriptors": "^2.0.3"
}
},
"uuid": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz",
"integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "2.3.4-beta",
"version": "2.3.6",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"copyright": "Kandra Labs, Inc.",
@@ -27,7 +27,7 @@
],
"dependencies": {
"@electron-elements/send-feedback": "1.0.7",
"@sentry/electron": "0.5.5",
"@sentry/electron": "0.8.1",
"adm-zip": "0.4.11",
"auto-launch": "5.0.5",
"electron-is-dev": "0.3.0",

View File

@@ -388,8 +388,7 @@ i.open-tab-button {
.selected-css-path,
.download-folder-path {
background: #eeeeee;
padding: 10px;
margin-top: 10px;
padding: 5px 10px;
margin-right: 10px;
display: flex;
width: 90%;
@@ -565,7 +564,7 @@ input.toggle-round:checked+label:after {
.certificate-input {
width:100%;
margin-top: 10px;
margin-top: 10px;
display:inline-flex;
}

View File

@@ -10,24 +10,26 @@ function handleExternalLink(event) {
const { url } = event;
const domainPrefix = DomainUtil.getDomain(this.props.index).url;
const downloadPath = ConfigUtil.getConfigItem('downloadsPath', `${app.getPath('downloads')}`);
// Whitelist URLs which are allowed to be opened in the app
const shouldShowInFolder = ConfigUtil.getConfigItem('showDownloadFolder', false);
// Whitelist URLs which are allowed to be opened in the app
const {
isInternalUrl: isWhiteListURL,
isUploadsUrl: isUploadsURL
} = LinkUtil.isInternal(domainPrefix, url);
isInternalUrl: isWhiteListURL,
isUploadsUrl: isUploadsURL
} = LinkUtil.isInternal(domainPrefix, url);
if (isWhiteListURL) {
event.preventDefault();
// download txt, pdf, mp3, mp4 etc.. by using downloadURL in the
// main process which allows the user to save the files to their desktop
// and not trigger webview reload while image in webview will
// do nothing and will not save it
// download txt, pdf, mp3, mp4 etc.. by using downloadURL in the
// main process which allows the user to save the files to their desktop
// and not trigger webview reload while image in webview will
// do nothing and will not save it
if (!LinkUtil.isImage(url) && isUploadsURL) {
ipcRenderer.send('downloadFile', url, downloadPath);
ipcRenderer.once('downloadFileCompleted', (event, filePath, fileName) => {
const downloadNotification = new Notification('Download Complete', {
body: `Click to open ${fileName}`,
body: shouldShowInFolder ? `Click to show ${fileName} in folder` : `Click to open ${fileName}`,
silent: true // We'll play our own sound - ding.ogg
});
@@ -37,7 +39,13 @@ function handleExternalLink(event) {
}
downloadNotification.onclick = () => {
shell.openItem(filePath);
if (shouldShowInFolder) {
// Reveal file in download folder
shell.showItemInFolder(filePath);
} else {
// Open file in the default native app
shell.openItem(filePath);
}
};
ipcRenderer.removeAllListeners('downloadFileFailed');
});
@@ -51,7 +59,7 @@ function handleExternalLink(event) {
return;
}
// open internal urls inside the current webview.
// open internal urls inside the current webview.
this.$el.loadURL(url);
} else {
event.preventDefault();

View File

@@ -0,0 +1,39 @@
const events = require('events');
const { ipcRenderer } = require('electron');
// we have and will have some non camelcase stuff
// while working with zulip so just turning the rule off
// for the whole file.
/* eslint-disable camelcase */
class ElectronBridge extends events {
send_event(...args) {
this.emit(...args);
}
on_event(...args) {
this.on(...args);
}
}
const electron_bridge = new ElectronBridge();
electron_bridge.on('total_unread_count', (...args) => {
ipcRenderer.send('unread-count', ...args);
});
electron_bridge.on('realm_name', (...args) => {
ipcRenderer.send('realm-name-changed', ...args);
});
electron_bridge.on('realm_icon_url', iconURL => {
const serverURL = location.origin;
iconURL = iconURL.includes('http') ? iconURL : `${serverURL}${iconURL}`;
ipcRenderer.send('realm-icon-changed', serverURL, iconURL);
});
// this follows node's idiomatic implementation of event
// emitters to make event handling more simpler instead of using
// functions zulip side will emit event using ElectronBrigde.send_event
// which is alias of .emit and on this side we can handle the data by adding
// a listener for the event.
module.exports = electron_bridge;

View File

@@ -16,8 +16,6 @@ const ReconnectUtil = require(__dirname + '/js/utils/reconnect-util.js');
const Logger = require(__dirname + '/js/utils/logger-util.js');
const { feedbackHolder } = require(__dirname + '/js/feedback.js');
const escape = require('escape-html');
const logger = new Logger({
file: 'errors.log',
timestamp: true
@@ -117,7 +115,8 @@ class ServerManagerView {
showNotification: true,
silent: false
},
downloadsPath: `${app.getPath('downloads')}`
downloadsPath: `${app.getPath('downloads')}`,
showDownloadFolder: false
};
// Platform specific settings
@@ -252,7 +251,7 @@ class ServerManagerView {
}
onHover(index, serverName) {
this.$serverIconTooltip[index].innerHTML = escape(serverName);
this.$serverIconTooltip[index].innerHTML = serverName;
this.$serverIconTooltip[index].removeAttribute('style');
// To handle position of servers' tooltip due to scrolling of list of organizations
// This could not be handled using CSS, hence the top of the tooltip is made same
@@ -396,6 +395,22 @@ class ServerManagerView {
const webContents = webview.getWebContents();
webContents.send('toggle-dnd', state, newSettings);
});
ipcRenderer.on('update-realm-icon', (event, serverURL, iconURL) => {
DomainUtil.getDomains().forEach((domain, index) => {
if (domain.url.includes(serverURL)) {
DomainUtil.saveServerIcon(iconURL).then(localIconUrl => {
const serverImgsSelector = `.tab .server-icons`;
const serverImgs = document.querySelectorAll(serverImgsSelector);
serverImgs[index].src = localIconUrl;
domain.icon = localIconUrl;
DomainUtil.db.push(`/domains[${index}]`, domain, true);
DomainUtil.reloadDB();
});
}
});
});
}
destroyTab(name, index) {

View File

@@ -4,6 +4,7 @@ const {
remote: { app }
} = require('electron');
const params = require('../utils/params-util.js');
const DefaultNotification = require('./default-notification');
const { appId, loadBots } = require('./helpers');
@@ -19,9 +20,8 @@ if (process.platform === 'darwin') {
}
window.addEventListener('load', () => {
// Call this function only when user is logged in
// eslint-disable-next-line no-undef, camelcase
if (page_params.realm_uri) {
if (params.isPageParams() && page_params.realm_uri) {
loadBots();
}
});

View File

@@ -97,6 +97,10 @@ class GeneralSection extends BaseSection {
</div>
<div class="title">Advanced</div>
<div class="settings-card">
<div class="setting-row" id="show-download-folder">
<div class="setting-description">Show downloaded file in the file manager</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="download-folder">
<div class="setting-description">
Default download location
@@ -108,6 +112,7 @@ class GeneralSection extends BaseSection {
<div class="download-folder-path">${ConfigUtil.getConfigItem('downloadsPath', `${app.getPath('downloads')}`)}</div>
</div>
</div>
</div>
<div class="title">Reset Application Data</div>
<div class="settings-card">
@@ -138,6 +143,7 @@ class GeneralSection extends BaseSection {
this.showCustomCSSPath();
this.removeCustomCSS();
this.downloadFolder();
this.showDownloadFolder();
// Platform specific settings
@@ -385,6 +391,18 @@ class GeneralSection extends BaseSection {
});
}
showDownloadFolder() {
this.generateSettingOption({
$element: document.querySelector('#show-download-folder .setting-control'),
value: ConfigUtil.getConfigItem('showDownloadFolder', false),
clickHandler: () => {
const newValue = !ConfigUtil.getConfigItem('showDownloadFolder');
ConfigUtil.setConfigItem('showDownloadFolder', newValue);
this.showDownloadFolder();
}
});
}
}
module.exports = GeneralSection;

View File

@@ -5,6 +5,7 @@ const SetupSpellChecker = require('./spellchecker');
const ConfigUtil = require(__dirname + '/utils/config-util.js');
const LinkUtil = require(__dirname + '/utils/link-util.js');
const params = require(__dirname + '/utils/params-util.js');
// eslint-disable-next-line import/no-unassigned-import
require('./notification');
@@ -12,6 +13,9 @@ require('./notification');
// Prevent drag and drop event in main process which prevents remote code executaion
require(__dirname + '/shared/preventdrag.js');
// eslint-disable-next-line camelcase
window.electron_bridge = require('./electron-bridge');
const logout = () => {
// Create the menu for the below
document.querySelector('.dropdown-toggle').click();
@@ -39,46 +43,44 @@ process.once('loaded', () => {
// To prevent failing this script on linux we need to load it after the document loaded
document.addEventListener('DOMContentLoaded', () => {
if (params.isPageParams()) {
// Get the default language of the server
const serverLanguage = page_params.default_language; // eslint-disable-line no-undef, camelcase
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');
if (getRestartButton) {
getRestartButton.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'reload-viewer');
});
}
// Open image attachment link in the lightbox instead of opening in the default browser
const { $, lightbox } = window;
$('#main_div').on('click', '.message_content p a', function (e) {
const url = $(this).attr('href');
if (serverLanguage) {
// Set spellcheker language
ConfigUtil.setConfigItem('spellcheckerLanguage', serverLanguage);
// Init spellchecker
SetupSpellChecker.init();
}
if (LinkUtil.isImage(url)) {
const $img = $(this).parent().siblings('.message_inline_image').find('img');
// redirect users to network troubleshooting page
const getRestartButton = document.querySelector('.restart_get_events_button');
if (getRestartButton) {
getRestartButton.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'reload-viewer');
// prevent the image link from opening in a new page.
e.preventDefault();
// prevent the message compose dialog from happening.
e.stopPropagation();
// Open image in the default browser if image preview is unavailable
if (!$img[0]) {
shell.openExternal(window.location.origin + url);
}
// Open image in lightbox
lightbox.open($img);
}
});
}
// Open image attachment link in the lightbox instead of opening in the default browser
const { $, lightbox } = window;
$('#main_div').on('click', '.message_content p a', function (e) {
const url = $(this).attr('href');
if (LinkUtil.isImage(url)) {
const $img = $(this).parent().siblings('.message_inline_image').find('img');
// prevent the image link from opening in a new page.
e.preventDefault();
// prevent the message compose dialog from happening.
e.stopPropagation();
// Open image in the default browser if image preview is unavailable
if (!$img[0]) {
shell.openExternal(window.location.origin + url);
}
// Open image in lightbox
lightbox.open($img);
}
});
});
// Clean up spellchecker events after you navigate away from this page;

View File

@@ -10,6 +10,8 @@ const escape = require('escape-html');
const Logger = require('./logger-util');
const CertificateUtil = require(__dirname + '/certificate-util.js');
const ProxyUtil = require(__dirname + '/proxy-util.js');
const ConfigUtil = require(__dirname + '/config-util.js');
const logger = new Logger({
file: `domain-util.log`,
@@ -119,8 +121,16 @@ class DomainUtil {
logger.warn('Error while trying to get certificate: ' + err);
}
}
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
// If certificate for the domain exists add it as a ca key in the request's parameter else consider only domain as the parameter for request
const checkDomain = (certificateLocation) ? ({url: domain + '/static/audio/zulip.ogg', ca: certificateLocation}) : domain + '/static/audio/zulip.ogg';
// Add proxy as a parameter if it sbeing used.
const checkDomain = {
url: domain + '/static/audio/zulip.ogg',
ca: (certificateLocation) ? certificateLocation : '',
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : ''
};
const serverConf = {
icon: defaultIconUrl,
@@ -193,9 +203,13 @@ class DomainUtil {
}
getServerSettings(domain) {
const serverSettingsUrl = domain + '/api/v1/server_settings';
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
const serverSettingsOptions = {
url: domain + '/api/v1/server_settings',
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : ''
};
return new Promise((resolve, reject) => {
request(serverSettingsUrl, (error, response) => {
request(serverSettingsOptions, (error, response) => {
if (!error && response.statusCode === 200) {
const data = JSON.parse(response.body);
if (data.hasOwnProperty('realm_icon') && data.realm_icon) {
@@ -215,12 +229,17 @@ class DomainUtil {
}
saveServerIcon(url) {
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
const serverIconOptions = {
url,
proxy: proxyEnabled ? ProxyUtil.getProxy(url) : ''
};
// The save will always succeed. If url is invalid, downgrade to default icon.
return new Promise(resolve => {
const filePath = this.generateFilePath(url);
const file = fs.createWriteStream(filePath);
try {
request(url).on('response', response => {
request(serverIconOptions).on('response', response => {
response.on('error', err => {
logger.log('Could not get server icon.');
logger.log(err);

View File

@@ -0,0 +1,15 @@
// This util function returns the page params if they're present else returns null
function isPageParams() {
let webpageParams = null;
try {
// eslint-disable-next-line no-undef, camelcase
webpageParams = page_params;
} catch (err) {
webpageParams = null;
}
return webpageParams;
}
module.exports = {
isPageParams
};

View File

@@ -1,5 +1,6 @@
'use strict';
const url = require('url');
const ConfigUtil = require('./config-util.js');
let instance = null;
@@ -15,6 +16,39 @@ class ProxyUtil {
return instance;
}
// Return proxy to be used for a particular uri, to be used for request
getProxy(uri) {
uri = url.parse(uri);
const proxyRules = ConfigUtil.getConfigItem('proxyRules', '').split(';');
// If SPS is on and system uses no proxy then request should not try to use proxy from
// environment. NO_PROXY = '*' makes request ignore all environment proxy variables.
if (proxyRules[0] === '') {
process.env.NO_PROXY = '*';
return;
}
const proxyRule = {};
if (uri.protocol === 'http:') {
proxyRules.forEach(proxy => {
if (proxy.includes('http=')) {
proxyRule.hostname = proxy.split('http=')[1].trim().split(':')[0];
proxyRule.port = proxy.split('http=')[1].trim().split(':')[1];
}
});
return proxyRule;
}
if (uri.protocol === 'https:') {
proxyRules.forEach(proxy => {
if (proxy.includes('https=')) {
proxyRule.hostname = proxy.split('https=')[1].trim().split(':')[0];
proxyRule.port = proxy.split('https=')[1].trim().split(':')[1];
}
});
return proxyRule;
}
}
resolveSystemProxy(mainWindow) {
const page = mainWindow.webContents;
const ses = page.session;

View File

@@ -5,6 +5,28 @@
All notable changes to the Zulip desktop app are documented in this file.
### v2.3.5 --2018-08-03
**New features**:
* Add a setting option to show downloaded file in file manager.
* Added electron bridge to communicate with webapp in real time.
**Fixes**:
* Fix failing attached file downloads.
* Fix page_params error.
* gulpfile: Update syntax and methods for gulp v4.x.
<hr>
### v2.3.4-beta --2018-07-24
**Fixes**:
* Fix downloading functionality of file attachments.
* Fix null of downloadPath when settings.json fails.
<hr>
### v2.3.3 --2018-07-14
**Enhancements**:
@@ -27,6 +49,7 @@ electron-builder: v20.20.4
electron-updater: v2.23.3
<hr>
### v2.3.2 --2018-05-28

View File

@@ -10,11 +10,11 @@ gulp.task('dev', () => {
// Start browser process
electron.start();
// Restart browser process
gulp.watch('app/main/*.js', ['restart:browser']);
gulp.watch('app/main/*.js', gulp.series('restart:browser'));
// Reload renderer process
gulp.watch('app/renderer/css/*.css', ['reload:renderer']);
gulp.watch('app/renderer/*.html', ['reload:renderer']);
gulp.watch('app/renderer/js/**/*.js', ['reload:renderer']);
gulp.watch('app/renderer/css/*.css', gulp.series('reload:renderer'));
gulp.watch('app/renderer/*.html', gulp.series('reload:renderer'));
gulp.watch('app/renderer/js/**/*.js', gulp.series('reload:renderer'));
});
gulp.task('restart:browser', done => {
@@ -36,4 +36,4 @@ gulp.task('test-e2e', () => {
}));
});
gulp.task('default', ['dev', 'test-e2e']);
gulp.task('default', gulp.parallel('dev', 'test-e2e'));

105
help.md
View File

@@ -1,105 +0,0 @@
# User Guide
> Welcome! This guide will walk you through the basics of using Zulip Desktop.
## Get Zulip Desktop
## Connect to a Server
### Connect through a proxy
It's possible to connect to your server through a proxy.
You can enter the proxy settings in the `Network` section of App Settings.
There are three fields provided:
* `PAC script` - The URL associated with the PAC file.
* `Proxy rules` - Rules indicating which proxies to use.
* `Proxy bypass rules` - Rules indicating which URLs should
bypass the proxy settings.
For a typical setup where internet access is required to use an HTTP proxy,
but URLs on the local network should be accessed directly, configure as follows:
`Proxy rules = proxy.example.com`
Your HTTP proxy server
`Proxy bypass rules = *.example.com;10.0.0.0/8`
Directly connect to your own domain and private IP subnet
for more complex setups, read below to configure complex proxy rules and proxy bypass rules.
### Sets the proxy settings.
When `PAC script` and `Proxy rules` are provided together, the `Proxy rules`
option is ignored and `PAC script` configuration is applied.
The `Proxy rules` has to follow the rules below:
```
proxyRules = schemeProxies[";"<schemeProxies>]
schemeProxies = [<urlScheme>"="]<proxyURIList>
urlScheme = "http" | "https" | "ftp" | "socks"
proxyURIList = <proxyURL>[","<proxyURIList>]
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
```
For example:
* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and
HTTP proxy `foopy2:80` for `ftp://` URLs.
* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs.
* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing
over to `bar` if `foopy:80` is unavailable, and after that using no proxy.
* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs.
* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail
over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable.
* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no
proxy if `foopy` is unavailable.
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
`socks4://foopy2` for all other URLs.
The `Proxy bypass rules` is a comma separated list of rules described below:
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
Match all hostnames that match the pattern HOSTNAME_PATTERN.
Examples:
"foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99",
"https://x.*.y.com:99"
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
Match a particular domain suffix.
Examples:
".google.com", ".com", "http://.google.com"
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
Match URLs which are IP address literals.
Examples:
"127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99"
* `IP_LITERAL "/" PREFIX_LENGHT_IN_BITS`
Match any URL that is to an IP literal that falls between the
given range. IP range is specified using CIDR notation.
Examples:
"192.168.1.1/16", "fefe:13::abc/33".
* `<local>`
Match local addresses. The meaning of `<local>` is whether the
host matches one of: "127.0.0.1", "::1", "localhost".
## Change App Preferences
## Reporting an Issue

14
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "zulip",
"version": "2.3.4-beta",
"version": "2.3.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -11,9 +11,9 @@
"dev": true
},
"@types/node": {
"version": "8.10.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.21.tgz",
"integrity": "sha512-87XkD9qDXm8fIax+5y7drx84cXsu34ZZqfB7Cial3Q/2lxSoJ/+DRaWckkCbxP41wFSIrrb939VhzaNxj4eY1w==",
"version": "8.10.26",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.26.tgz",
"integrity": "sha512-opk6bLLErLSwyVVJeSH5Ek7ZWOBSsN0JrvXTNVGLXLAXKB9xlTYajrplR44xVyMrmbut94H6uJ9jqzM/12jxkA==",
"dev": true
},
"abbrev": {
@@ -2091,9 +2091,9 @@
"dev": true
},
"electron": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-2.0.1.tgz",
"integrity": "sha512-piSwY2P7L6NWx672MNdSvtGPdQP/mhwAg8ICN6ofTTItPkd7D6kNHBPkq+DXwZcXVH1EifYR9yD/l3Xw1haVpQ==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-2.0.8.tgz",
"integrity": "sha512-pbeGFbwijb5V3Xy/KMcwIp59eA9igg2br+7EHbbwQoa3HRDF5JjTrciX7OiscCA52+ze2n4q38S4lXPqRitgIA==",
"dev": true,
"requires": {
"@types/node": "^8.0.24",

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "2.3.4-beta",
"version": "2.3.6",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
@@ -123,7 +123,7 @@
"assert": "1.4.1",
"cp-file": "^5.0.0",
"devtron": "1.4.0",
"electron": "2.0.1",
"electron": "2.0.8",
"electron-builder": "20.20.4",
"electron-connect": "0.6.2",
"electron-debug": "1.4.0",

185
tests/e2e/package.json Normal file
View File

@@ -0,0 +1,185 @@
{
"name": "zulip",
"productName": "ZulipTest",
"version": "2.3.3",
"main": "../../app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"copyright": "Kandra Labs, Inc.",
"author": {
"name": "Kandra Labs, Inc.",
"email": "support@zulipchat.com"
},
"repository": {
"type": "git",
"url": "https://github.com/zulip/zulip-electron.git"
},
"bugs": {
"url": "https://github.com/zulip/zulip-electron/issues"
},
"engines": {
"node": ">=6.0.0"
},
"scripts": {
"start": "electron app --disable-http-cache --no-electron-connect",
"reinstall": "node ./tools/reinstall-node-modules.js",
"postinstall": "electron-builder install-app-deps",
"test": "xo",
"test-e2e": "gulp test-e2e",
"dev": "gulp dev & nodemon --watch app/main --watch app/renderer --exec 'npm test' -e html,css,js",
"pack": "electron-builder --dir",
"dist": "electron-builder",
"mas": "electron-builder --mac mas",
"travis": "cd ./scripts && ./travis-build-test.sh",
"build-locales": "node tools/locale-helper"
},
"pre-commit": [
"test"
],
"build": {
"appId": "org.zulip.zulip-electron",
"asar": true,
"files": [
"**/*",
"!docs${/*}",
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
],
"copyright": "©2017 Kandra Labs, Inc.",
"mac": {
"category": "public.app-category.productivity",
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"linux": {
"category": "Chat;GNOME;GTK;Network;InstantMessaging",
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
"description": "Zulip Desktop Client for Linux",
"target": [
"deb",
"zip",
"AppImage",
"snap"
],
"maintainer": "Akash Nimare <svnitakash@gmail.com>",
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"deb": {
"synopsis": "Zulip Desktop App",
"afterInstall": "./scripts/debian-add-repo.sh",
"afterRemove": "./scripts/debian-uninstaller.sh"
},
"snap": {
"synopsis": "Zulip Desktop App"
},
"dmg": {
"background": "build/appdmg.png",
"icon": "build/icon.icns",
"iconSize": 100,
"contents": [
{
"x": 380,
"y": 280,
"type": "link",
"path": "/Applications"
},
{
"x": 110,
"y": 280,
"type": "file"
}
],
"window": {
"width": 500,
"height": 500
}
},
"win": {
"target": [
{
"target": "nsis-web",
"arch": [
"x64",
"ia32"
]
}
],
"icon": "build/icon.ico",
"publisherName": "Kandra Labs, Inc."
},
"nsis": {
"perMachine": true,
"oneClick": false,
"allowToChangeInstallationDirectory": true
}
},
"keywords": [
"Zulip",
"Group Chat app",
"electron-app",
"electron",
"Desktop app",
"InstantMessaging"
],
"devDependencies": {
"assert": "1.4.1",
"cp-file": "^5.0.0",
"devtron": "1.4.0",
"electron": "2.0.1",
"electron-builder": "20.20.4",
"electron-connect": "0.6.2",
"electron-debug": "1.4.0",
"google-translate-api": "2.3.0",
"gulp": "^4.0.0",
"gulp-tape": "0.0.9",
"is-ci": "^1.0.10",
"nodemon": "^1.14.11",
"pre-commit": "1.2.2",
"spectron": "3.8.0",
"tap-colorize": "^1.2.0",
"tape": "^4.8.0",
"xo": "0.18.2"
},
"xo": {
"parserOptions": {
"sourceType": "script",
"ecmaFeatures": {
"globalReturn": true
}
},
"esnext": true,
"overrides": [
{
"files": "app*/**/*.js",
"rules": {
"max-lines": [
"warn",
{
"max": 500,
"skipBlankLines": true,
"skipComments": true
}
],
"no-warning-comments": 0,
"object-curly-spacing": 0,
"capitalized-comments": 0,
"no-else-return": 0,
"no-path-concat": 0,
"no-alert": 0,
"guard-for-in": 0,
"prefer-promise-reject-errors": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": 0,
"no-prototype-builtins": 0
}
}
],
"ignore": [
"tests/e2e/*.js",
"tools/locale-helper/*.js"
],
"envs": [
"node",
"browser",
"mocha"
]
}
}