Compare commits

...

37 Commits

Author SHA1 Message Date
Akash Nimare
6f74fea0f3 release: New release v3.0.0. 2019-05-21 02:58:23 +05:30
Akash Nimare
405d938223 Update docs and code to point to new repo url.
This is because we have changed the repo name to zulip-desktop.
2019-05-21 02:33:13 +05:30
ViPuL
c6b7e9a9ee settings: Add option to toggle Error Reporting.
Adds an option to enable or disable sentry error
reporting under Advanced section in General Settings. 
Handles both main and renderer processes.

Also, changes the domain used to resolve proxy
in proxy-util from google.com to example.com.

Fixes #702.
2019-05-15 15:00:22 +05:30
Akash Nimare
b4073ba7ac Update package.json 2019-05-12 03:24:23 +05:30
Akash Nimare
b504f31c26 config: Remove unused icon file. 2019-05-12 03:20:22 +05:30
Akash Nimare
f71660b3f0 builder: Update electron-builder to v20.40.2. 2019-05-12 03:16:38 +05:30
Akash Nimare
5d0516887d windows: Add a config for installer name.
There is a bug with electron-builder where it doesn't name the installer properly. 
Without this config, it always names the installer with spaces in between 
i.e. "Zulip Web Setup.exe".
2019-05-12 03:14:41 +05:30
ViPuL
0dd86f0814 nsis: Allow installing app without admin previliges.
Allow the nsis installer to install the app to
AppData for a single user so that administrator
previliges are not required while installing.

Fixes #720.
2019-05-12 02:46:19 +05:30
Rhythm Sharma
eaecc92055 spellchecker: Use server language for spellchecker for all platforms.
This is an experimental fix for spellchecker. Previously, we were only using this on macOS since on other platforms, the spellcheck-module claimed to auto-detect + switch language on the fly but looks like it's not working as expected.
2019-05-10 03:43:49 +05:30
ViPuL
4f65c36a72 menu: Remove minimize and close from File menu.
Remove duplicate entries of minimize and close from
File menu as they are already present in Window menu.
2019-05-04 14:57:58 +05:30
ViPuL
2380b650c9 focus: Fix focus after clicking back button.
Addresses the issue of the webview not being in focus
after the Back button is clicked. Now, the webview is focused
explicitly by calling focus() on click.
2019-05-03 22:03:03 +05:30
ViPuL
1d713f1df2 logs: Limit the number of lines in log files.
Limits the numbers of lines in log files to 500.

Fixes a part of #727.
2019-05-03 14:57:00 +05:30
ViPuL
7fa9c291cb lint: Implement HTML Linting with htmlhint and fix indent.
* lint: Implement HTML Linting with htmlhint and fix indent.

Implements HTML linting using htmlhint and uses
indentation rules of zulip webapp - 4 spaces.
Creates a separate file .htmlhintrc for the rules, most
of which are defaults. Also, fixes indentation in html
files and adds a missing title in about.html.

* deps: Change versioning of various dependencies to exact versions.

As we prefer to use exact working version
for dependencies, changed the versions to
exact versions.

Fixes #676.
2019-04-24 00:44:01 +05:30
ViPuL
8a40e36a63 lint: Update css lint config to match zulip config.
Updated .stylelintrc to match zulip webapp's
.stylelintrc file. Also, made the required changes
to all CSS files.

Fixes remaining CSS part of #676.
2019-04-21 17:10:26 +05:30
Kanishk Kakar
3456720135 Unify case across menus and settings.
* menu: Convert to title case.

Also, change corresponding shortcuts to title case.

* settings: Convert options to sentence case.
2019-04-18 19:38:01 +05:30
Abhigyan Khaund
43840a5245 webview: Add "role" key to webview property. 2019-04-18 19:35:21 +05:30
ViPuL
d99c29301e lint: Implement CSS linting with stylelint.
* lint: Implement CSS linting with stylelint.
* lint: Format CSS files according to lintconfig.

Adds CSS linting following the rules of zulip webapp.
Some rules have been ommitted because they required
significant changes in code. Also, creates a separate
.stylelintrc for storing css config.

Fixes CSS part of #676.
2019-04-15 16:54:02 +05:30
ViPuL
6e760973ff shortcut: Allow zoom options from numpad.
Numpad keys by default aren't supported by electron
for using in menu accelarators. Uses a workaround to
make zoom options work with Numpad keys.

Fixes: #344.
2019-04-12 17:16:04 +05:30
Rhythm Sharma
88c64e9dd6 docs: improve development guide.
Update development instructions for all the systems.
2019-04-12 17:11:08 +05:30
Rhythm Sharma
e9db11c156 shortcuts-section: Fix tip's place for Windows & Linux. 2019-04-12 17:03:15 +05:30
ViPuL
8e8de212d8 menu: Reorder file menu and add option to Add Organization.
Reorder the File Menu. Also, adds a new option to
add a new organization to the file menu.
2019-04-10 22:03:43 +05:30
Puneeth Chaganti
0e0d7e7c4a webview: Work around buggy focus switching in Electron 3.0.10.
This commit works around a couple of bugs, which seem to be upstream bugs in the
current version of Electron.

First, `webContents.isFocused()` seems to be true even if we just switched to
a tab, and are trying to set it as the focused element. To work around this, we
check if the `webview` element is the same as `document.activeElement`.

Also, as per https://github.com/electron/electron/issues/15718, it looks like
`blur` needs to be called on the currently active element, before switching
focus on another element i.e., calling `focus` on it.

Fixes: #634.
2019-04-05 15:34:39 +05:30
ViPuL
6b98a49245 webview: fix focus after soft reload.
Fixes: #697.
2019-04-04 20:35:31 +05:30
ViPuL
8e5c326d74 context-menu: Add option to copy zulip url.
Added, "copy Zulip URL" in 
* Context menu in left sidebar 
* Application menu item

Fixes: #649.
2019-04-04 00:35:23 +05:30
Rhythm Sharma
862e9e2c8c DND: Fix text for Toggle DND in sidebar on hover. 2019-04-04 00:21:59 +05:30
Akash Nimare
8a0b047d8f snap: Update snap config.
Updating the config as suggested by the snap community here - 
https://forum.snapcraft.io/t/snap-fails-to-load-error-minidump-segmentation-fault/8691/5

Should improve #593.
2019-04-03 16:37:33 +05:30
Akash Nimare
4a833ef603 docs: Fix typo error in issue template. 2019-04-02 16:13:44 +05:30
ViPuL
fefb7247d8 domain-util: add requestOptions to replace request instances.
This simplifies the request instances.

Fixes #603.
2019-04-02 16:11:23 +05:30
ViPuL
54a6903236 sidebar: Fix organization cycling using Ctrl+Tab.
This fixes two issues -
a) While on the first server, Ctrl+Shift+Tab doesn't work. This fixes that and now cycles to the last active webview.
b) Disable org cycling for non-server pages likes settings.

Fixes #691.
2019-04-01 17:34:08 +05:30
Rhythm Sharma
92ef1bd532 settings: Modify reset app data button. 2019-03-23 16:20:34 +05:30
Kanishk Kakar
bf2e04b3bb sidebar: Switch to next server on Ctrl+Tab.
* Adds a new option to the Window menu that allows users to change to the
next organization cyclically. Activated by Ctrl + Tab.
* Switch to the previous server on Ctrl + Shift + Tab.
2019-03-20 22:15:25 +05:30
ViPuL
3e389ea5db requests: Allow insecure requests on user request.
In certain requests like for fetching realm icons, request tries to verify server certificate and fails when the user has chosen to ignore cert warnings and has not uploaded the cert.
In those cases, we should mark that this server verification is ignored and ask request to ignore the cert verification bypassing that parameter.

Fixes #684.
2019-03-18 23:18:06 +05:30
SankalpSh
8edff28daa changelog: Fix grammatical errors. 2019-03-13 14:04:44 +05:30
Kanishk Kakar
ef6abbf49e settings: Default to starting app on login.
Acts on an observation that it is easier to turn off auto-start on login
than it is to turn on.
2019-03-12 20:35:20 +05:30
Ján Hrnko
0f638dd4b5 docs: Fix broken link.
Fix broken link http://jlord.us/essential-electron/ to https://jlord.dev/blog/essential-electron
2019-03-02 23:33:54 +05:30
Akash Nimare
92f0e46927 New beta release v2.5.0. 2019-03-01 18:51:38 +05:30
Rhythm Sharma
a0dd3832c2 settings: Shorcut section horizontal alignment fix. 2019-02-18 17:11:27 +05:30
39 changed files with 3454 additions and 876 deletions

View File

@@ -2,7 +2,7 @@
<!-- Please Include: -->
- **Operating System**:
- [ ] Windows
- [ ] Linux/Ubutnu
- [ ] Linux/Ubuntu
- [ ] macOS
- **Clear steps to reproduce the issue**:
- **Relevant error messages and/or screenshots**:

25
.htmlhintrc Normal file
View File

@@ -0,0 +1,25 @@
{
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"attr-value-not-empty": false,
"attr-no-duplication": true,
"doctype-first": true,
"tag-pair": true,
"empty-tag-not-self-closed": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"title-require": true,
"alt-require": false,
"doctype-html5": true,
"id-class-value": "dash",
"style-disabled": false,
"inline-style-disabled": false,
"inline-script-disabled": false,
"space-tab-mixed-disabled": "space4",
"id-class-ad-disabled": false,
"href-abs-or-rel": false,
"attr-unsafe-chars": true,
"head-script-disabled": true
}

67
.stylelintrc Normal file
View File

@@ -0,0 +1,67 @@
{
"rules": {
# Stylistic rules for CSS.
"function-comma-space-after": "always",
"function-comma-space-before": "never",
"function-max-empty-lines": 0,
"function-whitespace-after": "always",
"value-keyword-case": "lower",
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
"value-list-max-empty-lines": 0,
"unit-case": "lower",
"property-case": "lower",
"color-hex-case": "lower",
"declaration-bang-space-before": "always",
"declaration-colon-newline-after": "always-multi-line",
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"declaration-block-semicolon-newline-after": "always",
"declaration-block-semicolon-space-before": "never",
"declaration-block-trailing-semicolon": "always",
"block-closing-brace-empty-line-before": "never",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always",
"block-opening-brace-newline-after": "always",
"block-opening-brace-space-before": "always",
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-descendant-combinator-no-non-space": true,
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "double",
"selector-type-case": "lower",
"selector-list-comma-newline-after": "always",
"selector-list-comma-space-before": "never",
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-name-case": "lower",
"media-feature-parentheses-space-inside": "never",
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"media-query-list-comma-newline-after": "always",
"media-query-list-comma-space-before": "never",
"at-rule-name-case": "lower",
"at-rule-name-space-after": "always",
"at-rule-semicolon-newline-after": "always",
"at-rule-semicolon-space-before": "never",
"comment-whitespace-inside": "always",
"indentation": 4,
# Limit language features
"color-no-hex": true,
"color-named": "never",
}
}

View File

@@ -2,20 +2,20 @@
Thanks for taking the time to contribute!
The following is a set of guidelines for contributing to Zulip Electron Desktop Client. These are just guidelines, not rules, so use your best judgement and feel free to propose changes to this document in a pull request.
The following is a set of guidelines for contributing to Zulip's desktop Client. These are just guidelines, not rules, so 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.
Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron, please head over to [this](https://jlord.dev/blog/essential-electron) great article.
## Community
* The whole Zulip documentation, such as setting up a development environment, setting up with the Zulip webapp project, and testing, 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 on [chat.zulip.org](https://chat.zulip.org/#narrow/stream/16-desktop).
* If you have any questions regarding zulip-desktop, open an [issue](https://github.com/zulip/zulip-desktop/issues/new/) or ask it on [chat.zulip.org](https://chat.zulip.org/#narrow/stream/16-desktop).
## 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 bug, open a [new issue](https://github.com/zulip/zulip-electron/issues/new).
Ensure the bug was not already reported by searching on GitHub under [issues](https://github.com/zulip/zulip-desktop/issues). If you're unable to find an open issue addressing the bug, open a [new issue](https://github.com/zulip/zulip-desktop/issues/new).
The [zulipbot](https://github.com/zulip/zulipbot) helps to claim an 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).
@@ -38,7 +38,7 @@ For example:
## Pull Requests
Pull Requests are always welcome.
Pull Requests are always welcome.
1. When you edit the code, please run `npm run test` to check the formatting of your code before you `git commit`.
2. Ensure the PR description clearly describes the problem and solution. It should include:

View File

@@ -1,6 +1,6 @@
# Zulip Desktop Client
[![Build Status](https://travis-ci.org/zulip/zulip-electron.svg?branch=master)](https://travis-ci.org/zulip/zulip-electron)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/zulip/zulip-electron?branch=master&svg=true)](https://ci.appveyor.com/project/akashnimare/zulip-electron/branch/master)
[![Build Status](https://travis-ci.org/zulip/zulip-desktop.svg?branch=master)](https://travis-ci.org/zulip/zulip-desktop)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/zulip/zulip-desktop?branch=master&svg=true)](https://ci.appveyor.com/project/zulip/zulip-desktop/branch/master)
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://chat.zulip.org)
@@ -20,7 +20,7 @@ Please see the [installation guide](https://zulipchat.com/help/desktop-app-insta
# Contribute
First, join us on the [Zulip community server](https://zulip.readthedocs.io/en/latest/contributing/chat-zulip-org.html)!
First, join us on the [Zulip community server](https://zulip.readthedocs.io/en/latest/contributing/chat-zulip-org.html)!
Also see our [contribution guidelines](./CONTRIBUTING.md) and our [development guide](./development.md).
# License

View File

@@ -159,7 +159,10 @@ app.on('ready', () => {
}
// Initialize sentry for main process
sentryInit();
const errorReporting = ConfigUtil.getConfigItem('errorReporting');
if (errorReporting) {
sentryInit();
}
const isSystemProxy = ConfigUtil.getConfigItem('useSystemProxy');
@@ -344,6 +347,12 @@ app.on('ready', () => {
ipcMain.on('realm-icon-changed', (event, serverURL, iconURL) => {
page.send('update-realm-icon', serverURL, iconURL);
});
// Using event.sender.send instead of page.send here to
// make sure the value of errorReporting is sent only once on load.
ipcMain.on('error-reporting', event => {
event.sender.send('error-reporting-val', errorReporting);
});
});
app.on('before-quit', () => {

View File

@@ -14,7 +14,7 @@ const logger = new Logger({
});
function linuxUpdateNotification() {
let url = 'https://api.github.com/repos/zulip/zulip-electron/releases';
let url = 'https://api.github.com/repos/zulip/zulip-desktop/releases';
url = ConfigUtil.getConfigItem('betaUpdate') ? url : url + '/latest';
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');

View File

@@ -49,7 +49,7 @@ class AppMenu {
{
label: `Release Notes`,
click() {
shell.openExternal(`https://github.com/zulip/zulip-electron/releases/tag/v${app.getVersion()}`);
shell.openExternal(`https://github.com/zulip/zulip-desktop/releases/tag/v${app.getVersion()}`);
}
}, {
type: 'separator'
@@ -226,6 +226,28 @@ class AppMenu {
type: 'checkbox'
});
}
initialSubmenu.push({
type: 'separator'
});
initialSubmenu.push({
label: 'Switch to Next Organization',
accelerator: `Ctrl+Tab`,
enabled: tabs[activeTabIndex].props.role === 'server',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('switch-server-tab', AppMenu.getNextServer(tabs, activeTabIndex));
}
}
}, {
label: 'Switch to Previous Organization',
accelerator: `Ctrl+Shift+Tab`,
enabled: tabs[activeTabIndex].props.role === 'server',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('switch-server-tab', AppMenu.getPreviousServer(tabs, activeTabIndex));
}
}
});
}
return initialSubmenu;
@@ -237,6 +259,21 @@ class AppMenu {
return [{
label: `${app.getName()}`,
submenu: [{
label: 'Add Organization',
accelerator: 'Cmd+Shift+N',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('new-server');
}
}
}, {
label: 'Toggle Do Not Disturb',
accelerator: 'Cmd+Shift+M',
click() {
const dndUtil = DNDUtil.toggle();
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
}
}, {
label: 'Desktop Settings',
accelerator: 'Cmd+,',
click(item, focusedWindow) {
@@ -256,14 +293,15 @@ class AppMenu {
}, {
type: 'separator'
}, {
label: 'Toggle Do Not Disturb',
accelerator: 'Command+Shift+M',
click() {
const dndUtil = DNDUtil.toggle();
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
label: 'Copy Zulip URL',
accelerator: 'Cmd+Shift+C',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('copy-zulip-url');
}
}
}, {
label: 'Log Out',
label: 'Log Out of Organization',
accelerator: 'Cmd+L',
enabled: enableMenu,
click(item, focusedWindow) {
@@ -332,22 +370,11 @@ class AppMenu {
return [{
label: '&File',
submenu: [{
label: 'Desktop Settings',
accelerator: 'Ctrl+,',
label: 'Add Organization',
accelerator: 'Ctrl+Shift+N',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('open-settings');
}
}
}, {
type: 'separator'
}, {
label: 'Keyboard Shortcuts',
accelerator: 'Ctrl+Shift+K',
enabled: enableMenu,
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('shortcut');
AppMenu.sendAction('new-server');
}
}
}, {
@@ -360,7 +387,34 @@ class AppMenu {
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
}
}, {
label: 'Log Out',
label: 'Desktop Settings',
accelerator: 'Ctrl+,',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('open-settings');
}
}
}, {
label: 'Keyboard Shortcuts',
accelerator: 'Ctrl+Shift+K',
enabled: enableMenu,
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('shortcut');
}
}
}, {
type: 'separator'
}, {
label: 'Copy Zulip URL',
accelerator: 'Ctrl+Shift+C',
click(item, focusedWindow) {
if (focusedWindow) {
AppMenu.sendAction('copy-zulip-url');
}
}
}, {
label: 'Log Out of Organization',
accelerator: 'Ctrl+L',
enabled: enableMenu,
click(item, focusedWindow) {
@@ -427,6 +481,23 @@ class AppMenu {
static checkForUpdate() {
appUpdater(true);
}
static getNextServer(tabs, activeTabIndex) {
do {
activeTabIndex = (activeTabIndex + 1) % tabs.length;
}
while (tabs[activeTabIndex].props.role !== 'server');
return activeTabIndex;
}
static getPreviousServer(tabs, activeTabIndex) {
do {
activeTabIndex = (activeTabIndex - 1 + tabs.length) % tabs.length;
}
while (tabs[activeTabIndex].props.role !== 'server');
return activeTabIndex;
}
static resetAppSettings() {
const resetAppSettingsMessage = 'By proceeding you will be removing all connected organizations and preferences from Zulip.';

2
app/package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "zulip",
"version": "2.4.0",
"version": "2.5.0-beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "2.4.0",
"version": "3.0.0",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
"copyright": "Kandra Labs, Inc.",
@@ -11,10 +11,10 @@
},
"repository": {
"type": "git",
"url": "https://github.com/zulip/zulip-electron.git"
"url": "https://github.com/zulip/zulip-desktop.git"
},
"bugs": {
"url": "https://github.com/zulip/zulip-electron/issues"
"url": "https://github.com/zulip/zulip-desktop/issues"
},
"main": "main/index.js",
"keywords": [

View File

@@ -1,46 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/about.css">
</head>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/about.css">
<title>Zulip - About</title>
</head>
<body>
<div class="about">
<img class="logo" src="../resources/zulip.png" />
<p class="detail" id="version">v?.?.?</p>
<div class="maintenance-info">
<p class="detail maintainer">
Maintained by
<a onclick="linkInBrowser('website')">Zulip</a>
</p>
<p class="detail license">
Available under the
<a onclick="linkInBrowser('license')">Apache 2.0 License</a>
</p>
</div>
</div>
<script>
<body>
<div class="about">
<img class="logo" src="../resources/zulip.png" />
<p class="detail" id="version">v?.?.?</p>
<div class="maintenance-info">
<p class="detail maintainer">
Maintained by
<a onclick="linkInBrowser('website')">Zulip</a>
</p>
<p class="detail license">
Available under the
<a onclick="linkInBrowser('license')">Apache 2.0 License</a>
</p>
</div>
</div>
<script>
const { app } = require('electron').remote;
const { shell } = require('electron');
const version_tag = document.querySelector('#version');
version_tag.innerHTML = 'v' + app.getVersion();
const { app } = require('electron').remote;
const { shell } = require('electron');
const version_tag = document.querySelector('#version');
version_tag.innerHTML = 'v' + app.getVersion();
function linkInBrowser(type) {
let url;
switch (type) {
case 'website':
url = "https://zulipchat.com";
break;
case 'license':
url = "https://github.com/zulip/zulip-electron/blob/master/LICENSE";
break;
}
shell.openExternal(url);
}
</script>
<script>require('./js/shared/preventdrag.js')</script>
</body>
function linkInBrowser(type) {
let url;
switch (type) {
case 'website':
url = "https://zulipchat.com";
break;
case 'license':
url = "https://github.com/zulip/zulip-desktop/blob/master/LICENSE";
break;
}
shell.openExternal(url);
}
</script>
<script>require('./js/shared/preventdrag.js')</script>
</body>
</html>

View File

@@ -1,66 +1,66 @@
body {
background: #fafafa;
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: subpixel-antialiased;
background: rgba(250, 250, 250, 1.000);
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: subpixel-antialiased;
}
.logo {
display: block;
margin: -40px auto;
display: block;
margin: -40px auto;
}
#version {
color: #444343;
font-size: 1.3em;
padding-top: 40px;
color: rgba(68, 67, 67, 1.000);
font-size: 1.3em;
padding-top: 40px;
}
.about {
margin: 25vh auto;
height: 25vh;
text-align: center;
margin: 25vh auto;
height: 25vh;
text-align: center;
}
.about p {
font-size: 20px;
color: rgba(0, 0, 0, 0.62);
font-size: 20px;
color: rgba(0, 0, 0, 0.62);
}
.about img {
width: 150px;
width: 150px;
}
.detail {
text-align: center;
text-align: center;
}
.detail.maintainer {
font-size: 1.2em;
font-weight: 500;
font-size: 1.2em;
font-weight: 500;
}
.detail.license {
font-size: 0.8em;
font-size: 0.8em;
}
.maintenance-info {
cursor: pointer;
position: absolute;
width: 100%;
left: 0px;
color: #444;
cursor: pointer;
position: absolute;
width: 100%;
left: 0px;
color: rgba(68, 68, 68, 1.000);
}
.maintenance-info p {
margin: 0;
font-size: 1em;
width: 100%;
margin: 0;
font-size: 1em;
width: 100%;
}
p.detail a {
color: #355f4c;
color: rgba(53, 95, 76, 1.000);
}
p.detail a:hover {
text-decoration: underline;
text-decoration: underline;
}

View File

@@ -16,7 +16,7 @@ body {
}
.toggle-sidebar {
background: #222c31;
background: rgba(34, 44, 49, 1.000);
width: 54px;
padding: 27px 0 20px 0;
justify-content: space-between;
@@ -43,25 +43,25 @@ body {
}
#view-controls-container {
height: calc(100% - 208px);
overflow-y: hidden;
height: calc(100% - 208px);
overflow-y: hidden;
}
#view-controls-container:hover {
overflow-y: overlay;
overflow-y: overlay;
}
#view-controls-container::-webkit-scrollbar {
width: 4px;
width: 4px;
}
#view-controls-container::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}
#view-controls-container::-webkit-scrollbar-thumb {
background-color: darkgrey;
outline: 1px solid slategrey;
background-color: rgba(169, 169, 169, 1.000);
outline: 1px solid rgba(169, 169, 169, 1.000);
}
@font-face {
@@ -119,12 +119,12 @@ body {
}
.action-button i {
color: #6c8592;
color: rgba(108, 133, 146, 1.000);
font-size: 28px;
}
.action-button:hover i {
color: #98a9b3;
color: rgba(152, 169, 179, 1.000);
}
.action-button.disable {
@@ -136,18 +136,18 @@ body {
}
.action-button.disable:hover i {
color: #6c8592;
color: rgba(108, 133, 146, 1.000);
}
.action-button.active {
/* background-color: rgba(255, 255, 255, 0.25); */
background-color: #efefef;
background-color: rgba(239, 239, 239, 1.000);
opacity: 0.9;
padding-right: 14px;
}
.action-button.active i {
color: #1c262b;
color: rgba(28, 38, 43, 1.000);
}
.tab:first-child {
@@ -177,7 +177,7 @@ body {
margin-top: 5px;
z-index: 11;
line-height: 31px;
color: #eee;
color: rgba(238, 238, 238, 1.000);
text-align: center;
overflow: hidden;
opacity: 0.6;
@@ -188,7 +188,7 @@ body {
font-family: Verdana;
font-weight: 600;
font-size: 22px;
border: 2px solid #222c31;
border: 2px solid rgba(34, 44, 49, 1.000);
margin-left: 17%;
width: 35px;
border-radius: 4px;
@@ -216,7 +216,7 @@ body {
.tab.active .server-tab {
opacity: 1;
background-color: #648478;
background-color: rgba(100, 132, 120, 1.000);
}
.tab .server-tab-badge.active {
@@ -224,7 +224,7 @@ body {
min-width: 11px;
padding: 0 3px;
height: 17px;
background-color: #f44336;
background-color: rgba(244, 67, 54, 1.000);
font-size: 10px;
font-family: sans-serif;
position: absolute;
@@ -232,7 +232,7 @@ body {
z-index: 15;
top: 6px;
float: right;
color: #fff;
color: rgba(255, 255, 255, 1.000);
text-align: center;
line-height: 17px;
display: block;
@@ -260,7 +260,7 @@ body {
}
.tab .server-tab-shortcut {
color: #648478;
color: rgba(100, 132, 120, 1.000);
font-size: 12px;
text-align: center;
font-family: sans-serif;
@@ -278,19 +278,19 @@ body {
width: 100%;
}
/*Pseudo element for loading indicator*/
/* Pseudo element for loading indicator */
#webviews-container::before {
content: "";
position: absolute;
z-index: 1;
background: #fff url(../img/ic_loading.gif) no-repeat;
background: rgba(255, 255, 255, 1.000) url(../img/ic_loading.gif) no-repeat;
background-size: 60px 60px;
background-position: center;
width: 100%;
height: 100%;
}
/*When the active webview is loaded*/
/* When the active webview is loaded */
#webviews-container.loaded::before {
opacity: 0;
z-index: -1;
@@ -333,27 +333,27 @@ webview.focus {
#reload-tooltip,
#setting-tooltip {
font-family: sans-serif;
background: #222c31;
background: rgba(34, 44, 49, 1.000);
margin-left: 48px;
padding: 6px 8px;
position: absolute;
margin-top: 0px;
z-index: 1000;
color: white;
color: rgba(255, 255, 255, 1.000);
border-radius: 4px;
text-align: center;
width: 55px;
font-size: 14px;
}
#dnd-tooltip:after,
#back-tooltip:after,
#reload-tooltip:after,
#setting-tooltip:after {
#dnd-tooltip::after,
#back-tooltip::after,
#reload-tooltip::after,
#setting-tooltip::after {
content: " ";
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
border-right: 8px solid #222c31;
border-right: 8px solid rgba(34, 44, 49, 1.000);
position: absolute;
top: 7px;
right: 68px;
@@ -362,25 +362,25 @@ webview.focus {
#add-server-tooltip,
.server-tooltip {
font-family: 'arial';
background: #222c31;
background: rgba(34, 44, 49, 1.000);
left: 56px;
padding: 10px 20px;
position: fixed;
margin-top: 11px;
z-index: 5000 !important;
color: #fff;
color: rgba(255, 255, 255, 1.000);
border-radius: 4px;
text-align: center;
width: max-content;
font-size: 14px;
}
#add-server-tooltip:after,
.server-tooltip:after {
#add-server-tooltip::after,
.server-tooltip::after {
content: " ";
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
border-right: 8px solid #222c31;
border-right: 8px solid rgba(34, 44, 49, 1.000);
position: absolute;
top: 10px;
left: -5px;
@@ -392,14 +392,14 @@ webview.focus {
position: absolute;
width: 24px;
height: 24px;
background: #222c31;
background: rgba(34, 44, 49, 1.000);
border-radius: 20px;
cursor: pointer;
box-shadow: #999 1px 1px;
box-shadow: rgba(153, 153, 153, 1.000) 1px 1px;
}
#collapse-button i {
color: #efefef;
color: rgba(239, 239, 239, 1.000);
}
#main-container {
@@ -420,8 +420,8 @@ webview.focus {
.popup .popuptext {
visibility: hidden;
background-color: #555;
color: #fff;
background-color: rgba(85, 85, 85, 1.000);
color: rgba(255, 255, 255, 1.000);
text-align: center;
border-radius: 6px;
padding: 9px 0;
@@ -453,24 +453,24 @@ webview.focus {
}
send-feedback {
width: 60%;
height: 85%;
width: 60%;
height: 85%;
}
#feedback-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 67, 67, 0.81);
align-items: center;
justify-content: center;
z-index: 2;
transition: all 1s ease-out;
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 67, 67, 0.81);
align-items: center;
justify-content: center;
z-index: 2;
transition: all 1s ease-out;
}
#feedback-modal.show {
display: flex;
display: flex;
}

View File

@@ -1,10 +1,11 @@
html, body {
html,
body {
margin: 0;
cursor: default;
font-size: 14px;
color: #333;
background: #fff;
user-select:none;
color: rgba(51, 51, 51, 1.000);
background: rgba(255, 255, 255, 1.000);
user-select: none;
}
#content {
@@ -27,8 +28,8 @@ html, body {
#reconnect {
font-size: 16px;
background: #009688;
color: #fff;
background: rgba(0, 150, 136, 1.000);
color: rgba(255, 255, 255, 1.000);
width: 84px;
height: 32px;
border-radius: 5px;

View File

@@ -7,25 +7,25 @@ body {
font-family: menu, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
background: #efefef;
background: rgba(239, 239, 239, 1.000);
letter-spacing: -.08px;
line-height: 18px;
color: #8b8e8f;
color: rgba(139, 142, 143, 1.000);
}
kbd {
display: inline-block;
border: 1px solid #ccc;
border: 1px solid rgba(204, 204, 204, 1.000);
border-radius: 4px;
font-size: 15px;
font-family: Courier New, Courier, monospace;
font-weight: bold;
white-space: nowrap;
background-color: #f7f7f7;
color: #333;
background-color: rgba(247, 247, 247, 1.000);
color: rgba(51, 51, 51, 1.000);
margin: 0 0.1em;
padding: 0.3em 0.8em;
text-shadow: 0 1px 0 #fff;
text-shadow: 0 1px 0 rgba(255, 255, 255, 1.000);
line-height: 1.4;
}
@@ -33,7 +33,7 @@ table,
th,
td {
border-collapse: collapse;
color: #383430;
color: rgba(56, 52, 48, 1.000);
}
table {
@@ -43,11 +43,11 @@ table {
}
table tr:nth-child(even) {
background-color: #fafafa;
background-color: rgba(250, 250, 250, 1.000);
}
table tr:nth-child(odd) {
background-color: #fff;
background-color: rgba(255, 255, 255, 1.000);
}
td {
@@ -103,7 +103,7 @@ td:nth-child(odd) {
display: flex;
flex-direction: column;
font-size: 16px;
background: #f2f2f2;
background: rgba(242, 242, 242, 1.000);
}
#nav-container {
@@ -112,18 +112,18 @@ td:nth-child(odd) {
.nav {
padding: 7px 0;
color: #999;
color: rgba(153, 153, 153, 1.000);
cursor: pointer;
}
.nav.active {
color: #4ebfac;
color: rgba(78, 191, 172, 1.000);
cursor: default;
position: relative;
}
.nav.active::before {
background: #464e5a;
background: rgba(70, 78, 90, 1.000);
width: 3px;
height: 18px;
position: absolute;
@@ -139,7 +139,7 @@ td:nth-child(odd) {
#settings-header {
font-size: 22px;
color: #222c31;
color: rgba(34, 44, 49, 1.000);
font-weight: bold;
text-transform: uppercase;
}
@@ -159,11 +159,11 @@ td:nth-child(odd) {
.title {
font-weight: 500;
color: #222c31;
color: rgba(34, 44, 49, 1.000);
}
.page-title {
color: #222c31;
color: rgba(34, 44, 49, 1.000);
font-size: 15px;
font-weight: bold;
padding: 4px 0 6px 0;
@@ -182,7 +182,7 @@ td:nth-child(odd) {
.sub-title {
padding: 4px 0 6px 0;
font-weight: bold;
color: #616161;
color: rgba(97, 97, 97, 1.000);
}
img.server-info-icon {
@@ -249,14 +249,14 @@ img.server-info-icon {
font-size: 14px;
border-radius: 4px;
padding: 13px;
border: #ededed 2px solid;
border: rgba(237, 237, 237, 1.000) 2px solid;
outline-width: 0;
background: transparent;
max-width: 450px;
}
.setting-input-value:focus {
border: #4EBFAC 2px solid;
border: rgba(78, 191, 172, 1.000) 2px solid;
}
.manual-proxy-block {
@@ -266,7 +266,7 @@ img.server-info-icon {
.actions-container {
display: flex;
font-size: 14px;
color: #235d3a;
color: rgba(35, 93, 58, 1.000);
vertical-align: middle;
margin: 10px 0;
flex-wrap: wrap;
@@ -287,6 +287,7 @@ img.server-info-icon {
.settings-pane {
flex-grow: 1;
min-width: 550px;
}
.action:hover {
@@ -298,7 +299,7 @@ img.server-info-icon {
}
.action.disabled {
color: #999;
color: rgba(153, 153, 153, 1.000);
}
.settings-card {
@@ -306,7 +307,7 @@ img.server-info-icon {
flex-wrap: wrap;
padding: 12px 30px;
margin: 10px 0 20px 0;
background: #fff;
background: rgba(255, 255, 255, 1.000);
width: 80%;
transition: all 0.2s;
}
@@ -321,21 +322,29 @@ img.server-info-icon {
}
.red {
color: #ef5350;
padding: 8px;
border: rgba(239, 83, 80, 0.5) solid 1px;
color: rgb(240, 148, 148);
background: rgba(255, 255, 255, 1.000);
border-radius: 4px;
border-color: #fff;
display: inline-block;
border: 2px solid rgb(240, 148, 148);
padding: 10px;
width: 100px;
cursor: pointer;
font-size: 1rem;
font-weight: bold;
transition: background-color 0.2s ease;
text-decoration: none;
text-align: center;
}
.red:hover {
background-color: rgba(230, 52, 49, 0.5);
color: #fff;
background-color: rgb(240, 148, 148);
color: rgba(255, 255, 255, 1.000);
}
.green {
color: #fff;
background: #4EBFAC;
color: rgba(255, 255, 255, 1.000);
background: rgba(78, 191, 172, 1.000);
border-radius: 4px;
display: inline-block;
border: none;
@@ -350,8 +359,8 @@ img.server-info-icon {
}
.green:hover {
background-color: #3c9f8d;
color: #fff;
background-color: rgba(60, 159, 141, 1.000);
color: rgba(255, 255, 255, 1.000);
}
.w-150 {
@@ -363,9 +372,9 @@ img.server-info-icon {
}
.grey {
color: #9E9E9E;
background: #FAFAFA;
border: 1px solid #9E9E9E;
color: rgba(158, 158, 158, 1.000);
background: rgba(250, 250, 250, 1.000);
border: 1px solid rgba(158, 158, 158, 1.000);
}
.setting-row {
@@ -392,7 +401,7 @@ i.open-tab-button {
.selected-css-path,
.download-folder-path {
background: #eeeeee;
background: rgba(238, 238, 238, 1.000);
padding: 5px 10px;
margin-right: 10px;
display: flex;
@@ -432,7 +441,7 @@ i.open-tab-button {
visibility: hidden;
}
.toggle+label {
.toggle + label {
display: block;
position: relative;
cursor: pointer;
@@ -440,16 +449,16 @@ i.open-tab-button {
user-select: none;
}
input.toggle-round+label {
input.toggle-round + label {
padding: 2px;
width: 50px;
height: 25px;
background-color: #dddddd;
background-color: rgba(221, 221, 221, 1.000);
border-radius: 25px;
}
input.toggle-round+label:before,
input.toggle-round+label:after {
input.toggle-round + label::before,
input.toggle-round + label::after {
display: block;
position: absolute;
top: 2px;
@@ -458,8 +467,8 @@ input.toggle-round+label:after {
content: "";
}
input.toggle-round+label:before {
background-color: #f1f1f1;
input.toggle-round + label::before {
background-color: rgba(241, 241, 241, 1.000);
border-radius: 25px;
top: 0;
right: 0px;
@@ -467,22 +476,22 @@ input.toggle-round+label:before {
bottom: 0px;
}
input.toggle-round+label:after {
input.toggle-round + label::after {
width: 25px;
height: 25px;
background-color: #fff;
background-color: rgba(255, 255, 255, 1.000);
border-radius: 100%;
}
input.toggle-round:checked+label:before {
background-color: #4EBFAC;
input.toggle-round:checked + label::before {
background-color: rgba(78, 191, 172, 1.000);
top: 0;
right: 0px;
left: 0px;
bottom: 0px;
}
input.toggle-round:checked+label:after {
input.toggle-round:checked + label::after {
margin-left: 25px;
}
@@ -499,17 +508,17 @@ input.toggle-round:checked+label:after {
width: 100%;
height: 100%;
/* background: rgba(61, 64, 67, 15); */
background: linear-gradient(35deg, #003b52, #45b59b);
background: linear-gradient(35deg, rgba(0, 59, 82, 1.000), rgba(69, 181, 155, 1.000));
overflow: auto;
}
/* Modal Content */
.modal-container {
background-color: #f4f7f8;
background-color: rgba(244, 247, 248, 1.000);
margin: auto;
padding: 57px;
border: #dae1e3 1px solid;
border: rgba(218, 225, 227, 1.000) 1px solid;
width: 550px;
height: 370px;
border-radius: 4px;
@@ -523,7 +532,7 @@ input.toggle-round:checked+label:after {
.divider {
margin-bottom: 30px;
margin-top: 30px;
color: #7d878a;
color: rgba(125, 135, 138, 1.000);
}
.divider hr {
@@ -554,8 +563,8 @@ input.toggle-round:checked+label:after {
margin: auto;
align-items: center;
text-align: center;
color: #fff;
background: #4EBFAC;
color: rgba(255, 255, 255, 1.000);
background: rgba(78, 191, 172, 1.000);
border-color: none;
border: none;
width: 98%;
@@ -565,15 +574,15 @@ input.toggle-round:checked+label:after {
}
.server-center button:hover {
background: #329588;
background: rgba(50, 149, 136, 1.000);
}
.server-center button:focus {
background: #329588;
background: rgba(50, 149, 136, 1.000);
}
.certificates-card {
width: 80%
width: 80%;
}
.certificate-input {
@@ -600,8 +609,8 @@ input.toggle-round:checked+label:after {
padding: 0;
}
.tip:hover{
box-shadow: none;
.tip:hover {
box-shadow: none;
}
.md-14 {
@@ -676,4 +685,4 @@ input.toggle-round:checked+label:after {
.action {
margin-top: 10px;
}
}
}

View File

@@ -1,9 +1,9 @@
/* Override css rules */
.portico-wrap>.header {
.portico-wrap > .header {
display: none;
}
.portico-container>.footer {
.portico-container > .footer {
display: none;
}

View File

@@ -95,6 +95,11 @@ class WebView extends BaseComponent {
}
this.loading = false;
this.show();
// Refocus text boxes after reload
// Remove when upstream issue https://github.com/electron/electron/issues/14474 is fixed
this.$el.blur();
this.$el.focus();
});
this.$el.addEventListener('did-fail-load', event => {
@@ -165,7 +170,13 @@ class WebView extends BaseComponent {
focus() {
// focus Webview and it's contents when Window regain focus.
const webContents = this.$el.getWebContents();
if (webContents && !webContents.isFocused()) {
// HACK: webContents.isFocused() seems to be true even without the element
// being in focus. So, we check against `document.activeElement`.
if (webContents && this.$el !== document.activeElement) {
// HACK: Looks like blur needs to be called on the previously focused
// element to transfer focus correctly, in Electron v3.0.10
// See https://github.com/electron/electron/issues/15718
document.activeElement.blur();
this.$el.focus();
webContents.focus();
}
@@ -214,6 +225,7 @@ class WebView extends BaseComponent {
back() {
if (this.$el.canGoBack()) {
this.$el.goBack();
this.focus();
}
}

View File

@@ -1,6 +1,6 @@
'use strict';
const { ipcRenderer, remote } = require('electron');
const { ipcRenderer, remote, clipboard } = require('electron');
const isDev = require('electron-is-dev');
const { session, app, Menu, dialog } = remote;
@@ -105,12 +105,13 @@ class ServerManagerView {
useSystemProxy: false,
showSidebar: true,
badgeOption: true,
startAtLogin: false,
startAtLogin: true,
startMinimized: false,
enableSpellchecker: true,
showNotification: true,
autoUpdate: true,
betaUpdate: false,
errorReporting: true,
customCSS: false,
silent: false,
lastActiveTab: 0,
@@ -186,6 +187,7 @@ class ServerManagerView {
index,
tabIndex,
url: server.url,
role: 'server',
name: CommonUtil.decodeString(server.alias),
isActive: () => {
return index === this.activeTabIndex;
@@ -337,6 +339,7 @@ class ServerManagerView {
index: this.functionalTabs[tabProps.name],
tabIndex,
url: tabProps.url,
role: 'function',
name: tabProps.name,
isActive: () => {
return this.functionalTabs[tabProps.name] === this.activeTabIndex;
@@ -512,7 +515,7 @@ class ServerManagerView {
// Toggles the dnd button icon.
toggleDNDButton(alert) {
this.$dndTooltip.textContent = (alert ? 'Turn Off' : 'Enable') + ' Do Not Disturb';
this.$dndTooltip.textContent = (alert ? 'Disable' : 'Enable') + ' Do Not Disturb';
this.$dndButton.querySelector('i').textContent = alert ? 'notifications_off' : 'notifications';
}
@@ -535,6 +538,12 @@ class ServerManagerView {
}
});
}
},
{
label: 'Copy Zulip URL',
click: () => {
clipboard.writeText(DomainUtil.getDomain(index).url);
}
}
];
const contextMenu = Menu.buildFromTemplate(template);
@@ -724,6 +733,14 @@ class ServerManagerView {
ipcRenderer.on('open-feedback-modal', () => {
feedbackHolder.classList.add('show');
});
ipcRenderer.on('copy-zulip-url', () => {
clipboard.writeText(DomainUtil.getDomain(this.activeTabIndex).url);
});
ipcRenderer.on('new-server', () => {
this.openSettings('AddServer');
});
}
}

View File

@@ -24,7 +24,7 @@ class GeneralSection extends BaseSection {
<div class="setting-control"></div>
</div>
<div class="setting-row" id="menubar-option" style= "display:${process.platform === 'darwin' ? 'none' : ''}">
<div class="setting-description">Auto hide Menubar (Press Alt key to display)</div>
<div class="setting-description">Auto hide menu bar (Press Alt key to display)</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="sidebar-option">
@@ -47,7 +47,7 @@ class GeneralSection extends BaseSection {
<div class="title">Desktop Notifications</div>
<div class="settings-card">
<div class="setting-row" id="show-notification-option">
<div class="setting-description">Show Desktop Notifications</div>
<div class="setting-description">Show desktop notifications</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="silent-option">
@@ -83,6 +83,10 @@ class GeneralSection extends BaseSection {
</div>
<div class="title">Advanced</div>
<div class="settings-card">
<div class="setting-row" id="enable-error-reporting">
<div class="setting-description">Enable error reporting (requires restart)</div>
<div class="setting-control"></div>
</div>
<div class="setting-row" id="show-download-folder">
<div class="setting-description">Show downloaded files in file manager</div>
<div class="setting-control"></div>
@@ -120,7 +124,7 @@ class GeneralSection extends BaseSection {
<div class="setting-row" id="resetdata-option">
<div class="setting-description">This will delete all application data including all added accounts and preferences
</div>
<button class="reset-data-button green w-150">Reset App Data</button>
<button class="reset-data-button red w-150">Reset App Data</button>
</div>
</div>
</div>
@@ -145,6 +149,7 @@ class GeneralSection extends BaseSection {
this.removeCustomCSS();
this.downloadFolder();
this.showDownloadFolder();
this.enableErrorReporting();
// Platform specific settings
@@ -319,6 +324,18 @@ class GeneralSection extends BaseSection {
});
}
enableErrorReporting() {
this.generateSettingOption({
$element: document.querySelector('#enable-error-reporting .setting-control'),
value: ConfigUtil.getConfigItem('errorReporting', true),
clickHandler: () => {
const newValue = !ConfigUtil.getConfigItem('errorReporting');
ConfigUtil.setConfigItem('errorReporting', newValue);
this.enableErrorReporting();
}
});
}
clearAppDataDialog() {
const clearAppDataMessage = 'By clicking proceed you will be removing all added accounts and preferences from Zulip. When the application restarts, it will be as if you are starting Zulip for the first time.';
const getAppPath = path.join(app.getPath('appData'), app.getName());

View File

@@ -130,6 +130,14 @@ class ShortcutsSection extends BaseSection {
<td><kbd>Option</kbd><kbd>${userOSKey}</kbd><kbd>U</kbd></td>
<td>Toggle DevTools for Active Tab</td>
</tr>
<tr>
<td><kbd>Ctrl</kbd> + <kbd>Tab</kbd></td>
<td>Switch to Next Organization</td>
</tr>
<tr>
<td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd></td>
<td>Switch to Previous Organization</td>
</tr>
</table>
<div class="setting-control"></div>
</div>
@@ -170,6 +178,7 @@ class ShortcutsSection extends BaseSection {
return `
<div class="settings-pane">
<div class="settings-card tip"><p><b><i class="material-icons md-14">settings</i>Tip: </b>These desktop app shortcuts extend the Zulip webapp's <span id="open-hotkeys-link"> keyboard shortcuts</span>.</p></div>
<div class="title">Application Shortcuts</div>
<div class="settings-card">
<table>
@@ -269,6 +278,14 @@ class ShortcutsSection extends BaseSection {
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd></td>
<td>Toggle DevTools for Active Tab</td>
</tr>
<tr>
<td><kbd>${userOSKey}</kbd> + <kbd>Tab</kbd></td>
<td>Switch to Next Organization</td>
</tr>
<tr>
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd></td>
<td>Switch to Previous Organization</td>
</tr>
</table>
<div class="setting-control"></div>
</div>
@@ -300,7 +317,6 @@ class ShortcutsSection extends BaseSection {
</table>
<div class="setting-control"></div>
</div>
<div class="tip"><b><i class="material-icons md-14">lightbulb_outline</i>Tip: </b>These desktop app shortcuts extend the Zulip webapp's <span id="open-hotkeys-link">keyboard shortcuts</span>.</div>
</div>
`;
}

View File

@@ -91,8 +91,15 @@ window.addEventListener('beforeunload', () => {
// electron's globalShortcut can cause unexpected results
// so adding the reload shortcut in the old-school way
// Zoom from numpad keys is not supported by electron, so adding it through listeners.
document.addEventListener('keydown', event => {
if (event.code === 'F5') {
ipcRenderer.send('forward-message', 'hard-reload');
} else if (event.ctrlKey && event.code === 'NumpadAdd') {
ipcRenderer.send('forward-message', 'zoomIn');
} else if (event.ctrlKey && event.code === 'NumpadSubtract') {
ipcRenderer.send('forward-message', 'zoomOut');
} else if (event.ctrlKey && event.code === 'Numpad0') {
ipcRenderer.send('forward-message', 'zoomActualSize');
}
});

View File

@@ -32,14 +32,7 @@ class SetupSpellChecker {
const userLanguage = ConfigUtil.getConfigItem('spellcheckerLanguage');
// eslint-disable-next-line no-unused-expressions
process.platform === 'darwin' ?
// On macOS, spellchecker fails to auto-detect the lanugage user is typing in
// that's why we need to mention it explicitly
this.SpellCheckHandler.switchLanguage(userLanguage) :
// On Linux and Windows, spellchecker can automatically detects the language the user is typing in
// and silently switches on the fly; thus we can start off as US English
this.SpellCheckHandler.switchLanguage('en-US');
this.SpellCheckHandler.switchLanguage(userLanguage);
}
const contextMenuBuilder = new ContextMenuBuilder(this.SpellCheckHandler);

View File

@@ -9,10 +9,7 @@ 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 SystemUtil = require(__dirname + '/../utils/system-util.js');
const RequestUtil = require(__dirname + '/../utils/request-util.js');
const logger = new Logger({
file: `domain-util.log`,
@@ -64,9 +61,10 @@ class DomainUtil {
}
addDomain(server) {
const ignoreCerts = server.ignoreCerts;
return new Promise(resolve => {
if (server.icon) {
this.saveServerIcon(server).then(localIconUrl => {
this.saveServerIcon(server, ignoreCerts).then(localIconUrl => {
server.icon = localIconUrl;
this.db.push('/domains[]', server, true);
this.reloadDB();
@@ -103,42 +101,25 @@ class DomainUtil {
return false;
}
checkDomain(domain, silent = false) {
// ignoreCerts parameter helps in fetching server icon and
// other server details when user chooses to ignore certificate warnings
checkDomain(domain, ignoreCerts = false, silent = false) {
if (!silent && this.duplicateDomain(domain)) {
// Do not check duplicate in silent mode
return Promise.reject('This server has been added.');
}
domain = this.formatUrl(domain);
const certificate = CertificateUtil.getCertificate(encodeURIComponent(domain));
let certificateLocation = '';
if (certificate) {
// To handle case where certificate has been moved from the location in certificates.json
try {
certificateLocation = fs.readFileSync(certificate);
} catch (err) {
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
// 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) : '',
ecdhCurve: 'auto',
headers: { 'User-Agent': SystemUtil.getUserAgent() }
...RequestUtil.requestOptions(domain, ignoreCerts)
};
const serverConf = {
icon: defaultIconUrl,
url: domain,
alias: domain
alias: domain,
ignoreCerts
};
return new Promise((resolve, reject) => {
@@ -155,14 +136,14 @@ class DomainUtil {
const certsError = error.toString().includes('certificate');
if (!error && response.statusCode < 400) {
// Correct
this.getServerSettings(domain).then(serverSettings => {
this.getServerSettings(domain, serverConf.ignoreCerts).then(serverSettings => {
resolve(serverSettings);
}, () => {
resolve(serverConf);
});
} else if (domain.indexOf(whitelistDomains) >= 0 || certsError) {
if (silent) {
this.getServerSettings(domain).then(serverSettings => {
this.getServerSettings(domain, serverConf.ignoreCerts).then(serverSettings => {
resolve(serverSettings);
}, () => {
resolve(serverConf);
@@ -185,7 +166,9 @@ class DomainUtil {
detail: certErrorDetail
}, response => {
if (response === 0) {
this.getServerSettings(domain).then(serverSettings => {
// set ignoreCerts parameter to true in case user responds with yes
serverConf.ignoreCerts = true;
this.getServerSettings(domain, serverConf.ignoreCerts).then(serverSettings => {
resolve(serverSettings);
}, () => {
resolve(serverConf);
@@ -205,27 +188,12 @@ class DomainUtil {
});
}
getServerSettings(domain) {
const certificate = CertificateUtil.getCertificate(encodeURIComponent(domain));
let certificateLocation = '';
if (certificate) {
// To handle case where certificate has been moved from the location in certificates.json
try {
certificateLocation = fs.readFileSync(certificate);
} catch (err) {
logger.warn('Error while trying to get certificate: ' + err);
}
}
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
getServerSettings(domain, ignoreCerts = false) {
const serverSettingsOptions = {
url: domain + '/api/v1/server_settings',
ca: (certificateLocation) ? certificateLocation : '',
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : '',
ecdhCurve: 'auto',
headers: { 'User-Agent': SystemUtil.getUserAgent() }
...RequestUtil.requestOptions(domain, ignoreCerts)
};
return new Promise((resolve, reject) => {
request(serverSettingsOptions, (error, response) => {
if (!error && response.statusCode === 200) {
@@ -236,7 +204,8 @@ class DomainUtil {
// Following check handles both the cases
icon: data.realm_icon.startsWith('/') ? data.realm_uri + data.realm_icon : data.realm_icon,
url: data.realm_uri,
alias: escape(data.realm_name)
alias: escape(data.realm_name),
ignoreCerts
});
}
} else {
@@ -246,31 +215,13 @@ class DomainUtil {
});
}
saveServerIcon(server) {
saveServerIcon(server, ignoreCerts = false) {
const url = server.icon;
const domain = server.url;
const certificate = CertificateUtil.getCertificate(encodeURIComponent(domain));
let certificateLocation = '';
if (certificate) {
// To handle case where certificate has been moved from the location in certificates.json
try {
certificateLocation = fs.readFileSync(certificate);
} catch (err) {
logger.warn('Error while trying to get certificate: ' + err);
}
}
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
// Add proxy and certificate as a parameter if its being used.
const serverIconOptions = {
url,
ca: (certificateLocation) ? certificateLocation : '',
proxy: proxyEnabled ? ProxyUtil.getProxy(url) : '',
ecdhCurve: 'auto',
headers: { 'User-Agent': SystemUtil.getUserAgent() }
...RequestUtil.requestOptions(domain, ignoreCerts)
};
// The save will always succeed. If url is invalid, downgrade to default icon.
@@ -305,8 +256,9 @@ class DomainUtil {
updateSavedServer(url, index) {
// Does not promise successful update
this.checkDomain(url, true).then(newServerConf => {
this.saveServerIcon(newServerConf).then(localIconUrl => {
const ignoreCerts = this.getDomain(index).ignoreCerts;
this.checkDomain(url, ignoreCerts, true).then(newServerConf => {
this.saveServerIcon(newServerConf, ignoreCerts).then(localIconUrl => {
newServerConf.icon = localIconUrl;
this.updateDomain(index, newServerConf);
this.reloadDB();

View File

@@ -1,14 +1,28 @@
const NodeConsole = require('console').Console;
const fs = require('fs');
const os = require('os');
const isDev = require('electron-is-dev');
const { initSetUp } = require('./default-util');
const { sentryInit, captureException } = require('./sentry-util');
initSetUp();
sentryInit();
let app = null;
let reportErrors = true;
if (process.type === 'renderer') {
app = require('electron').remote.app;
// Report Errors to Sentry only if it is enabled in settings
// Gets the value of reportErrors from config-util for renderer process
// For main process, sentryInit() is handled in index.js
const { ipcRenderer } = require('electron');
ipcRenderer.send('error-reporting');
ipcRenderer.on('error-reporting-val', (event, errorReporting) => {
reportErrors = errorReporting;
if (reportErrors) {
sentryInit();
}
});
} else {
app = require('electron').app;
}
@@ -30,6 +44,13 @@ class Logger {
timestamp = this.getTimestamp;
}
// Trim log according to type of process
if (process.type === 'renderer') {
requestIdleCallback(() => this.trimLog(file));
} else {
process.nextTick(() => this.trimLog(file));
}
const fileStream = fs.createWriteStream(file, { flags: 'a' });
const nodeConsole = new NodeConsole(fileStream);
@@ -86,7 +107,27 @@ class Logger {
}
reportSentry(err) {
captureException(err);
if (reportErrors) {
captureException(err);
}
}
trimLog(file) {
fs.readFile(file, 'utf8', (err, data) => {
if (err) {
throw err;
}
const MAX_LOG_FILE_LINES = 500;
const logs = data.split(os.EOL);
const logLength = logs.length - 1;
// Keep bottom MAX_LOG_FILE_LINES of each log instance
if (logLength > MAX_LOG_FILE_LINES) {
const trimmedLogs = logs.slice(logLength - MAX_LOG_FILE_LINES);
const toWrite = trimmedLogs.join(os.EOL);
fs.writeFileSync(file, toWrite);
}
});
}
}

View File

@@ -52,7 +52,7 @@ class ProxyUtil {
resolveSystemProxy(mainWindow) {
const page = mainWindow.webContents;
const ses = page.session;
const resolveProxyUrl = 'www.google.com';
const resolveProxyUrl = 'www.example.com';
// Check HTTP Proxy
const httpProxy = new Promise(resolve => {

View File

@@ -0,0 +1,62 @@
const fs = require('fs');
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 SystemUtil = require(__dirname + '/../utils/system-util.js');
const logger = new Logger({
file: `request-util.log`,
timestamp: true
});
let instance = null;
class RequestUtil {
constructor() {
if (!instance) {
instance = this;
}
return instance;
}
// ignoreCerts parameter helps in fetching server icon and
// other server details when user chooses to ignore certificate warnings
requestOptions(domain, ignoreCerts) {
domain = this.formatUrl(domain);
const certificate = CertificateUtil.getCertificate(
encodeURIComponent(domain)
);
let certificateLocation = '';
if (certificate) {
// To handle case where certificate has been moved from the location in certificates.json
try {
certificateLocation = fs.readFileSync(certificate);
} catch (err) {
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
// Add proxy as a parameter if it is being used.
return {
ca: certificateLocation ? certificateLocation : '',
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : '',
ecdhCurve: 'auto',
headers: { 'User-Agent': SystemUtil.getUserAgent() },
rejectUnauthorized: !ignoreCerts
};
}
formatUrl(domain) {
const hasPrefix = (domain.indexOf('http') === 0);
if (hasPrefix) {
return domain;
} else {
return (domain.indexOf('localhost:') >= 0) ? `http://${domain}` : `https://${domain}`;
}
}
}
module.exports = new RequestUtil();

View File

@@ -1,56 +1,56 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip</title>
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div class="popup">
<span class="popuptext hidden" id="fullscreen-popup"></span>
</div>
<div id="sidebar" class="toggle-sidebar">
<div id="view-controls-container">
<div id="tabs-container"></div>
<div id="add-tab" class="tab functional-tab">
<div class="server-tab" id="add-action">
<i class="material-icons">add</i>
<body>
<div id="content">
<div class="popup">
<span class="popuptext hidden" id="fullscreen-popup"></span>
</div>
<div id="sidebar" class="toggle-sidebar">
<div id="view-controls-container">
<div id="tabs-container"></div>
<div id="add-tab" class="tab functional-tab">
<div class="server-tab" id="add-action">
<i class="material-icons">add</i>
</div>
<span id="add-server-tooltip" style="display:none">Add organization</span>
</div>
</div>
<div id="actions-container">
<div class="action-button" id="dnd-action">
<i class="material-icons md-48">notifications</i>
<span id="dnd-tooltip" style="display:none">Do Not Disturb</span>
</div>
<div class="action-button" id="reload-action">
<i class="material-icons md-48">refresh</i>
<span id="reload-tooltip" style="display:none">Reload</span>
</div>
<div class="action-button disable" id="back-action">
<i class="material-icons md-48">arrow_back</i>
<span id="back-tooltip" style="display:none">Go Back</span>
</div>
<div class="action-button" id="settings-action">
<i class="material-icons md-48">settings</i>
<span id="setting-tooltip" style="display:none">Settings</span>
</div>
</div>
</div>
<div id="main-container">
<div id="webviews-container"></div>
</div>
</div>
<span id="add-server-tooltip" style="display:none">Add organization</span>
</div>
</div>
<div id="actions-container">
<div class="action-button" id="dnd-action">
<i class="material-icons md-48">notifications</i>
<span id="dnd-tooltip" style="display:none">Do Not Disturb</span>
</div>
<div class="action-button" id="reload-action">
<i class="material-icons md-48">refresh</i>
<span id="reload-tooltip" style="display:none">Reload</span>
</div>
<div class="action-button disable" id="back-action">
<i class="material-icons md-48">arrow_back</i>
<span id="back-tooltip" style="display:none">Go Back</span>
</div>
<div class="action-button" id="settings-action">
<i class="material-icons md-48">settings</i>
<span id="setting-tooltip" style="display:none">Settings</span>
</div>
</div>
</div>
<div id="main-container">
<div id="webviews-container"></div>
</div>
</div>
<div id="feedback-modal">
<send-feedback></send-feedback>
</div>
</body>
<script src="js/main.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
<div id="feedback-modal">
<send-feedback></send-feedback>
</div>
</body>
<script src="js/main.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
</html>

View File

@@ -1,22 +1,22 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Network Troubleshooting</title>
<link rel="stylesheet" href="css/network.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="picture"><img src="img/zulip_network.png"></div>
<div id="title">Zulip can't connect</div>
<div id="description">
<div>Your computer seems to be offline.</div>
<div>We will keep trying to reconnect, or you can try now.</div>
</div>
<div id="reconnect">Try now</div>
</div>
</body>
<script src="js/pages/network.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Network Troubleshooting</title>
<link rel="stylesheet" href="css/network.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="picture"><img src="img/zulip_network.png"></div>
<div id="title">Zulip can't connect</div>
<div id="description">
<div>Your computer seems to be offline.</div>
<div>We will keep trying to reconnect, or you can try now.</div>
</div>
<div id="reconnect">Try now</div>
</div>
</body>
<script src="js/pages/network.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
</html>

View File

@@ -1,17 +1,17 @@
<!DOCTYPE html>
<html lang="en" class="responsive desktop">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Settings</title>
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="sidebar"></div>
<div id="settings-container"></div>
</div>
</body>
<script src="js/pages/preference/preference.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<title>Zulip - Settings</title>
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
</head>
<body>
<div id="content">
<div id="sidebar"></div>
<div id="settings-container"></div>
</div>
</body>
<script src="js/pages/preference/preference.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -292,7 +292,7 @@ electron-updater - `v2.21.8`
* Setting page and left-sidebar UI improvements
* Other minor improvments
* Other minor improvements
@@ -419,7 +419,7 @@ electron-updater - `v2.21.8`
* Fixed a bug which was caused by app's shortcuts. From now on our shortcuts won't hijack other apps shortcuts
* Removed [electron-localshortcut](https://github.com/parro-it/electron-localshortcut) completely. Now we only depends on menu accelerators for keyboard shortcuts
* Removed [electron-localshortcut](https://github.com/parro-it/electron-localshortcut) completely. Now we only depend on menu accelerators for keyboard shortcuts
* Handle certificate issue properly
@@ -620,7 +620,7 @@ electron-updater - `v2.21.8`
* Properly signed app for macOS
* Toggle tray icon
* Better error handling when no internet connenction
* Better error handling when no internet connection
@@ -634,7 +634,7 @@ electron-updater - `v2.21.8`
### v0.5.8 --2017-02-13
**Enhacements**:
**Enhancements**:
Smaller Windows installer size
<hr>
@@ -650,7 +650,7 @@ Minor improvements
### v0.5.6 --2017-02-07
**Enhacements**:
**Enhancement**:
- Using NSIS instead of [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows) on Windows
@@ -672,9 +672,9 @@ Minor improvements
**Fixes**:
- Fixed :
- Auto-updates
- Spellchecker
- Zooming functionality
- Auto-updates
- Spellchecker
- Zooming functionality
- Removed unused node modules
- Using stable version for node modules
@@ -718,7 +718,7 @@ Minor improvements
### v0.5.1 --2016-11-23
**Enhacements**:
**Enhancement**:
- Added Spellchecker support with correct spell suggestions
@@ -759,6 +759,6 @@ Minor improvements
### v0.0.1-alpha -- 2016-08-31
**Enhacements**:
**Enhancement**:
* Added DMG installer for macOS

View File

@@ -1,85 +1,152 @@
# Improve development guide
# Development setup
This is a guide to running the Zulip desktop app from a source tree,
in order to contribute to developing it.
This is a guide to running the Zulip desktop app from a source tree, in order to contribute to developing it. The Zulip electron development environment can be installed on **macOS, Windows, and Linux** (Debian or Ubuntu recommended). Youll need at least **2GB of available RAM**. Installing the Zulip electron development environment requires downloading several hundred megabytes of dependencies, so you will need an **active, reasonably fast, internet connection throughout the entire installation processes.**
## Prerequisites
# Set up Git & GitHub
To build and run the app from source, you'll need the following:
You can skip this step if you already have Git, GitHub.
* [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node.js](https://nodejs.org) >= v6.9.0
* [NPM](https://www.npmjs.com/get-npm) and
[node-gyp](https://github.com/nodejs/node-gyp#installation),
if they don't come bundled with your Node.js installation
* [Python](https://www.python.org/downloads/release/python-2713/)
(v2.7.x recommended)
* A C++ compiler compatible with C++11
* Linux users also need [Snapcraft](https://snapcraft.io/)
* Development headers for the libXext, libXtst, and libxkbfile libraries
Follow our [Git Guide](https://zulip.readthedocs.io/en/latest/git/setup.html) in order to install Git, set up a GitHub account
### Debian/Ubuntu and friends
On a system running Debian, Ubuntu, or another Debian-based Linux
distribution, you can install all dependencies through the package
manager (see [here][nodesource-install] for more on the first command):
# Install Prerequisites
```sh
$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
$ sudo apt install git nodejs python build-essential snapcraft libxext-dev libxtst-dev libxkbfile-dev libgconf-2-4
```
Jump to:
[nodesource-install]: https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions
- [MacOS](https://github.com/zulip/zulip-desktop/blob/master/development.md#macos)
- [Ubuntu/Debian](https://github.com/zulip/zulip-desktop/blob/master/development.md#ubuntudebian)
- [Windows](https://github.com/zulip/zulip-desktop/blob/master/development.md#windows)
### Other OSes
Other developers run the app on Windows, macOS, and possibly other OSes.
PRs to add specific instructions to this doc are welcome!
## MacOS
On Windows, your C++ compiler should be Visual Studio 2015 or later.
## Download, build, and run
**Node JS**
Go to the [Node.js Downloads page](https://nodejs.org/en/download/). Download Node.js for MacOS (`v6.9.0` or above recommended). Run the downloaded Node.js `.pkg` Installer. You're finished! To ensure Node.js has been installed, run `node -v` in your terminal - you should get something like `v6.9.0` or above
Clone the source locally:
```sh
$ git clone https://github.com/zulip/zulip-electron
$ cd zulip-electron
```
Install project dependencies:
```sh
$ npm install
```
**if** [**NPM**](https://www.npmjs.com/get-npm) **and** [**node-gyp**](https://github.com/nodejs/node-gyp#installation) **don't come bundled with your Node.js installation, Download manually**
Start the app:
```sh
$ npm start
```
Start and watch changes:
```sh
$ npm run dev
```
Now you are ready for next step [: Get Zulip Desktop Code.](https://github.com/zulip/zulip-desktop/blob/master/development.md#get-zulip-desktop-code)
## Troubleshooting
If you have any problems running the app, see the [most common
issues](./troubleshooting.md).
## Ubuntu/Debian
## Making a release
To package the app into an installer:
```
npm run dist
```
If youre in a hurry, you can copy and paste the following into your terminal
This command will produce distributable packages or installers for the
operating system you're running on:
* on Windows, a Windows installer file
* on macOS, a `.dmg` file
* on Linux, a plain `.zip` file as well as a `.deb` file, `.snap` file and an
`AppImage` file.
To generate all three types, you will need all three operating
systems.
sudo apt install git nodejs node-gyp python build-essential snapcraft libxext-dev libxtst-dev lib xkbfile-dev libgconf-2-4
The output files appear in the `dist/` directory.
after pasting you can jump to next step [: Get Zulip Desktop Code](https://github.com/zulip/zulip-desktop/blob/master/development.md#get-zulip-desktop-code).
**For a step-by-step explanation, read on.**
1. **Node JS**
`$ sudo apt-get install nodejs`
2. **Install** [**Node-gyp**](https://github.com/nodejs/node-gyp#installation)
3. **Python (v2.7.x recommended)**
`$ sudo apt install python2.7`
4. **C++ compiler compatible with C++11**
`$ sudo apt install build-essential`
5. **Snapcraft**
`$ sudo apt install snapcraft`
6. **Development** **headers**
`$ sudo apt install libxext-dev libxtst-dev libxkbfile-dev libgconf-2-4`
**if** [**NPM**](https://www.npmjs.com/get-npm) **don't come bundled with your Node.js installation, Download manually**
Now you are ready for next step [: Get Zulip Desktop Code.](https://github.com/zulip/zulip-desktop/blob/master/development.md#get-zulip-desktop-code)
## Windows
**Node JS**
Go to the [Node.js Downloads page](https://nodejs.org/en/download/). Download Node.js for windows (`v6.9.0` or above recommended). Run the downloaded Node.js `.msi` Installer. You're finished! To ensure Node.js has been installed, run `node -v` in your terminal - you should get something like `v6.9.0` or above
**Followings are optional yet recommended prerequisites -**
**Cmder**
1. Download the [latest release](https://github.com/cmderdev/cmder/releases/)
2. Extract the archive. *Note: This path should not be* `C:\Program Files` *or anywhere else that would require Administrator access for modifying configuration files*
3. (optional) Place your own executable files into the `%cmder_root%\bin` folder to be injected into your PATH.
4. Run `Cmder.exe`
**Chocolatey**
You can download chocolatey from here https://chocolatey.org/ and for Installing Chocolatey on your machine follow this steps
1. First, ensure that you are using an administrative shell.
2. Copy the text specific to your command shell - [cmd.exe](https://chocolatey.org/install#install-with-cmdexe) or [powershell.exe](https://chocolatey.org/install#install-with-powershellexe).
3. Paste the copied text into your shell and press Enter.
4. Wait a few seconds for the command to complete.
5. If you don't see any errors, you are ready to use Chocolatey! Type `choco` or `choco -?`
**System specific dependencies**
- use only 32bit or 64bit for all of the installers, do not mix architectures
- install using default settings
- open Windows Powershell as Admin and paste this
C:\Windows\system32> npm install --global --production windows-build-tools
**if** [**NPM**](https://www.npmjs.com/get-npm) **and** [**node-gyp**](https://github.com/nodejs/node-gyp#installation) **don't come bundled with your Node.js installation, Download manually**
Now you are ready for next step [: Get Zulip Desktop Code.](https://github.com/zulip/zulip-desktop/blob/master/development.md#get-zulip-desktop-code)
# Get Zulip Desktop Code
1. In your browser, visit https://github.com/zulip/zulip-desktop and click the `fork` button. You will need to be logged in to GitHub to do this.
2. Open Terminal (macOS/Ubuntu) or Git BASH (Windows; must **run as an Administrator**).
3. In Terminal/Git BASH, [clone your fork of the zulip-desktop repository](https://github.com/zulip/zulip-desktop/blob/master/development.md#clone-to-your-machine) and [connect the zulip-desktop upstream repository](https://github.com/zulip/zulip-desktop/blob/master/development.md#connect-your-fork-to-zulip-desktop-upstream)
## Clone to your machine
1. On GitHub, navigate to the main page of your fork repository.
2. Under the repository name, click **Clone or download**.
3. In the Clone with HTTPs section, click to copy the clone URL for the repository.
4. Open Terminal, Change the current working directory to the location where you want the cloned directory to be made.
git clone https://github.com/YOURUSERNAME/zulip-desktop.git
Dont forget to replace YOURUSERNAME with your git username
## Connect your fork to zulip-desktop upstream
cd zulip-desktop
git remote add -f upstream https://github.com/zulip/zulip-desktop.git
# build and run
## Install project dependencies:
$ npm install
## There two ways to start the app:
**vanilla method**
$ npm start
**start and watch changes recommended for devs**
$ npm run dev

View File

@@ -21,8 +21,8 @@ C:\Windows\system32> npm install --global --production windows-build-tools
Clone the source locally:
```sh
$ git clone https://github.com/zulip/zulip-electron
$ cd zulip-electron
$ git clone https://github.com/zulip/zulip-desktop
$ cd zulip-desktop
```
Install project dependencies:

View File

@@ -1,3 +1,3 @@
### Want to contribute to this Wiki?
[Edit `/docs` files and send a pull request.](https://github.com/zulip/zulip-electron/tree/master/docs)
[Edit `/docs` files and send a pull request.](https://github.com/zulip/zulip-desktop/tree/master/docs)

View File

@@ -1,10 +1,10 @@
# How to install
**Note:** If you download from the [releases page](https://github.com/zulip/zulip-electron/releases), be careful what version you pick. Releases that end with `-beta` are beta releases and the rest are stable.
**Note:** If you download from the [releases page](https://github.com/zulip/zulip-desktop/releases), be careful what version you pick. Releases that end with `-beta` are beta releases and the rest are stable.
- **beta:** these releases are the right balance between getting new features early while staying away from nasty bugs.
- **stable:** these releases are more thoroughly tested; they receive new features later, but there's a lower chance that things will go wrong.
[LR]: https://github.com/zulip/zulip-electron/releases
[LR]: https://github.com/zulip/zulip-desktop/releases
## OS X

2965
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "2.4.0",
"version": "3.0.0",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
@@ -12,10 +12,10 @@
},
"repository": {
"type": "git",
"url": "https://github.com/zulip/zulip-electron.git"
"url": "https://github.com/zulip/zulip-desktop.git"
},
"bugs": {
"url": "https://github.com/zulip/zulip-electron/issues"
"url": "https://github.com/zulip/zulip-desktop/issues"
},
"engines": {
"node": ">=6.0.0"
@@ -24,7 +24,10 @@
"start": "electron app --disable-http-cache --no-electron-connect",
"reinstall": "node ./tools/reinstall-node-modules.js",
"postinstall": "electron-builder install-app-deps",
"test": "xo",
"lint-css": "stylelint app/renderer/css/*.css",
"lint-html": "./node_modules/.bin/htmlhint \"app/renderer/*.html\" ",
"lint-js": "xo",
"test": "npm run lint-html && npm run lint-css && npm run lint-js",
"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",
@@ -44,7 +47,7 @@
"!docs${/*}",
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
],
"copyright": "©2017 Kandra Labs, Inc.",
"copyright": "©2019 Kandra Labs, Inc.",
"mac": {
"category": "public.app-category.productivity",
"artifactName": "${productName}-${version}-${arch}.${ext}"
@@ -59,7 +62,7 @@
"AppImage",
"snap"
],
"maintainer": "Akash Nimare <svnitakash@gmail.com>",
"maintainer": "Akash Nimare <akash@zulipchat.com>",
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"deb": {
@@ -103,10 +106,13 @@
}
],
"icon": "build/icon.ico",
"artifactName": "${productName}-Web-Setup-${version}.${ext}",
"publisherName": "Kandra Labs, Inc."
},
"nsis": {
"allowToChangeInstallationDirectory": true
"allowToChangeInstallationDirectory": true,
"oneClick": false,
"perMachine": false
}
},
"keywords": [
@@ -119,21 +125,23 @@
],
"devDependencies": {
"assert": "1.4.1",
"cp-file": "^5.0.0",
"cp-file": "5.0.0",
"devtron": "1.4.0",
"electron": "3.0.10",
"electron-builder": "20.38.4",
"electron-builder": "20.40.2",
"electron-connect": "0.6.2",
"electron-debug": "1.4.0",
"google-translate-api": "2.3.0",
"gulp": "^4.0.0",
"gulp": "4.0.0",
"gulp-tape": "0.0.9",
"is-ci": "^1.0.10",
"nodemon": "^1.14.11",
"htmlhint": "0.11.0",
"is-ci": "1.0.10",
"nodemon": "1.14.11",
"pre-commit": "1.2.2",
"spectron": "^5.0.0",
"tap-colorize": "^1.2.0",
"tape": "^4.8.0",
"spectron": "5.0.0",
"stylelint": "9.10.1",
"tap-colorize": "1.2.0",
"tape": "4.8.0",
"xo": "0.18.2"
},
"xo": {
@@ -151,7 +159,7 @@
"max-lines": [
"warn",
{
"max": 600,
"max": 700,
"skipBlankLines": true,
"skipComments": true
}

View File

@@ -1,5 +1,5 @@
name: zulip
version: 2.0.0
version: 2.3.82
summary: Zulip Desktop Client for Linux
description: Zulip combines the immediacy of Slack with an email threading model. With Zulip, you can catch up on important conversations while ignoring irrelevant ones.
confinement: strict
@@ -34,4 +34,4 @@ parts:
- libxtst6
source: dist/linux-unpacked
after:
- desktop-gtk2
- desktop-gtk3

View File

@@ -48,10 +48,10 @@ envSetup()
# Set name of upstreamRemote
cd $workingDir
git remote -v | grep "github\.com.zulip.zulip-electron.git (fetch)" > /dev/null 2>&1
git remote -v | grep "github\.com.zulip.zulip-desktop.git (fetch)" > /dev/null 2>&1
if [ $? -eq 0 ]
then
upstreamRemote=`git remote -v | grep "github\.com.zulip.zulip-electron.git (fetch)" | awk '{ print $1 }'`
upstreamRemote=`git remote -v | grep "github\.com.zulip.zulip-desktop.git (fetch)" | awk '{ print $1 }'`
else
upstreamRemote="origin"
fi