mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-04 22:13:13 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f74fea0f3 | ||
|
|
405d938223 | ||
|
|
c6b7e9a9ee | ||
|
|
b4073ba7ac | ||
|
|
b504f31c26 | ||
|
|
f71660b3f0 | ||
|
|
5d0516887d | ||
|
|
0dd86f0814 | ||
|
|
eaecc92055 | ||
|
|
4f65c36a72 | ||
|
|
2380b650c9 | ||
|
|
1d713f1df2 | ||
|
|
7fa9c291cb | ||
|
|
8a40e36a63 | ||
|
|
3456720135 | ||
|
|
43840a5245 | ||
|
|
d99c29301e | ||
|
|
6e760973ff | ||
|
|
88c64e9dd6 | ||
|
|
e9db11c156 | ||
|
|
8e8de212d8 | ||
|
|
0e0d7e7c4a | ||
|
|
6b98a49245 | ||
|
|
8e5c326d74 | ||
|
|
862e9e2c8c | ||
|
|
8a0b047d8f | ||
|
|
4a833ef603 | ||
|
|
fefb7247d8 | ||
|
|
54a6903236 | ||
|
|
92ef1bd532 | ||
|
|
bf2e04b3bb | ||
|
|
3e389ea5db | ||
|
|
8edff28daa | ||
|
|
ef6abbf49e | ||
|
|
0f638dd4b5 | ||
|
|
92f0e46927 | ||
|
|
a0dd3832c2 |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
<!-- Please Include: -->
|
<!-- Please Include: -->
|
||||||
- **Operating System**:
|
- **Operating System**:
|
||||||
- [ ] Windows
|
- [ ] Windows
|
||||||
- [ ] Linux/Ubutnu
|
- [ ] Linux/Ubuntu
|
||||||
- [ ] macOS
|
- [ ] macOS
|
||||||
- **Clear steps to reproduce the issue**:
|
- **Clear steps to reproduce the issue**:
|
||||||
- **Relevant error messages and/or screenshots**:
|
- **Relevant error messages and/or screenshots**:
|
||||||
|
|||||||
25
.htmlhintrc
Normal file
25
.htmlhintrc
Normal 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
67
.stylelintrc
Normal 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",
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
Thanks for taking the time to contribute!
|
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
|
## 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
|
## 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).
|
* 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
|
## 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).
|
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
|
||||||
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`.
|
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:
|
2. Ensure the PR description clearly describes the problem and solution. It should include:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Zulip Desktop Client
|
# Zulip Desktop Client
|
||||||
[](https://travis-ci.org/zulip/zulip-electron)
|
[](https://travis-ci.org/zulip/zulip-desktop)
|
||||||
[](https://ci.appveyor.com/project/akashnimare/zulip-electron/branch/master)
|
[](https://ci.appveyor.com/project/zulip/zulip-desktop/branch/master)
|
||||||
[](https://github.com/sindresorhus/xo)
|
[](https://github.com/sindresorhus/xo)
|
||||||
[](https://chat.zulip.org)
|
[](https://chat.zulip.org)
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Please see the [installation guide](https://zulipchat.com/help/desktop-app-insta
|
|||||||
|
|
||||||
# Contribute
|
# 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).
|
Also see our [contribution guidelines](./CONTRIBUTING.md) and our [development guide](./development.md).
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|||||||
@@ -159,7 +159,10 @@ app.on('ready', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize sentry for main process
|
// Initialize sentry for main process
|
||||||
sentryInit();
|
const errorReporting = ConfigUtil.getConfigItem('errorReporting');
|
||||||
|
if (errorReporting) {
|
||||||
|
sentryInit();
|
||||||
|
}
|
||||||
|
|
||||||
const isSystemProxy = ConfigUtil.getConfigItem('useSystemProxy');
|
const isSystemProxy = ConfigUtil.getConfigItem('useSystemProxy');
|
||||||
|
|
||||||
@@ -344,6 +347,12 @@ app.on('ready', () => {
|
|||||||
ipcMain.on('realm-icon-changed', (event, serverURL, iconURL) => {
|
ipcMain.on('realm-icon-changed', (event, serverURL, iconURL) => {
|
||||||
page.send('update-realm-icon', 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', () => {
|
app.on('before-quit', () => {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const logger = new Logger({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function linuxUpdateNotification() {
|
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';
|
url = ConfigUtil.getConfigItem('betaUpdate') ? url : url + '/latest';
|
||||||
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
|
const proxyEnabled = ConfigUtil.getConfigItem('useManualProxy') || ConfigUtil.getConfigItem('useSystemProxy');
|
||||||
|
|
||||||
|
|||||||
115
app/main/menu.js
115
app/main/menu.js
@@ -49,7 +49,7 @@ class AppMenu {
|
|||||||
{
|
{
|
||||||
label: `Release Notes`,
|
label: `Release Notes`,
|
||||||
click() {
|
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'
|
type: 'separator'
|
||||||
@@ -226,6 +226,28 @@ class AppMenu {
|
|||||||
type: 'checkbox'
|
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;
|
return initialSubmenu;
|
||||||
@@ -237,6 +259,21 @@ class AppMenu {
|
|||||||
return [{
|
return [{
|
||||||
label: `${app.getName()}`,
|
label: `${app.getName()}`,
|
||||||
submenu: [{
|
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',
|
label: 'Desktop Settings',
|
||||||
accelerator: 'Cmd+,',
|
accelerator: 'Cmd+,',
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
@@ -256,14 +293,15 @@ class AppMenu {
|
|||||||
}, {
|
}, {
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
}, {
|
}, {
|
||||||
label: 'Toggle Do Not Disturb',
|
label: 'Copy Zulip URL',
|
||||||
accelerator: 'Command+Shift+M',
|
accelerator: 'Cmd+Shift+C',
|
||||||
click() {
|
click(item, focusedWindow) {
|
||||||
const dndUtil = DNDUtil.toggle();
|
if (focusedWindow) {
|
||||||
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
|
AppMenu.sendAction('copy-zulip-url');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
label: 'Log Out',
|
label: 'Log Out of Organization',
|
||||||
accelerator: 'Cmd+L',
|
accelerator: 'Cmd+L',
|
||||||
enabled: enableMenu,
|
enabled: enableMenu,
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
@@ -332,22 +370,11 @@ class AppMenu {
|
|||||||
return [{
|
return [{
|
||||||
label: '&File',
|
label: '&File',
|
||||||
submenu: [{
|
submenu: [{
|
||||||
label: 'Desktop Settings',
|
label: 'Add Organization',
|
||||||
accelerator: 'Ctrl+,',
|
accelerator: 'Ctrl+Shift+N',
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
AppMenu.sendAction('open-settings');
|
AppMenu.sendAction('new-server');
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
type: 'separator'
|
|
||||||
}, {
|
|
||||||
label: 'Keyboard Shortcuts',
|
|
||||||
accelerator: 'Ctrl+Shift+K',
|
|
||||||
enabled: enableMenu,
|
|
||||||
click(item, focusedWindow) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
AppMenu.sendAction('shortcut');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@@ -360,7 +387,34 @@ class AppMenu {
|
|||||||
AppMenu.sendAction('toggle-dnd', dndUtil.dnd, dndUtil.newSettings);
|
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',
|
accelerator: 'Ctrl+L',
|
||||||
enabled: enableMenu,
|
enabled: enableMenu,
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
@@ -427,6 +481,23 @@ class AppMenu {
|
|||||||
static checkForUpdate() {
|
static checkForUpdate() {
|
||||||
appUpdater(true);
|
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() {
|
static resetAppSettings() {
|
||||||
const resetAppSettingsMessage = 'By proceeding you will be removing all connected organizations and preferences from Zulip.';
|
const resetAppSettingsMessage = 'By proceeding you will be removing all connected organizations and preferences from Zulip.';
|
||||||
|
|
||||||
|
|||||||
2
app/package-lock.json
generated
2
app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"version": "2.4.0",
|
"version": "2.5.0-beta",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"productName": "Zulip",
|
"productName": "Zulip",
|
||||||
"version": "2.4.0",
|
"version": "3.0.0",
|
||||||
"description": "Zulip Desktop App",
|
"description": "Zulip Desktop App",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"copyright": "Kandra Labs, Inc.",
|
"copyright": "Kandra Labs, Inc.",
|
||||||
@@ -11,10 +11,10 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/zulip/zulip-electron.git"
|
"url": "https://github.com/zulip/zulip-desktop.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/zulip/zulip-electron/issues"
|
"url": "https://github.com/zulip/zulip-desktop/issues"
|
||||||
},
|
},
|
||||||
"main": "main/index.js",
|
"main": "main/index.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,46 +1,47 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="css/about.css">
|
<link rel="stylesheet" href="css/about.css">
|
||||||
</head>
|
<title>Zulip - About</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<img class="logo" src="../resources/zulip.png" />
|
<img class="logo" src="../resources/zulip.png" />
|
||||||
<p class="detail" id="version">v?.?.?</p>
|
<p class="detail" id="version">v?.?.?</p>
|
||||||
<div class="maintenance-info">
|
<div class="maintenance-info">
|
||||||
<p class="detail maintainer">
|
<p class="detail maintainer">
|
||||||
Maintained by
|
Maintained by
|
||||||
<a onclick="linkInBrowser('website')">Zulip</a>
|
<a onclick="linkInBrowser('website')">Zulip</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="detail license">
|
<p class="detail license">
|
||||||
Available under the
|
Available under the
|
||||||
<a onclick="linkInBrowser('license')">Apache 2.0 License</a>
|
<a onclick="linkInBrowser('license')">Apache 2.0 License</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const { app } = require('electron').remote;
|
const { app } = require('electron').remote;
|
||||||
const { shell } = require('electron');
|
const { shell } = require('electron');
|
||||||
const version_tag = document.querySelector('#version');
|
const version_tag = document.querySelector('#version');
|
||||||
version_tag.innerHTML = 'v' + app.getVersion();
|
version_tag.innerHTML = 'v' + app.getVersion();
|
||||||
|
|
||||||
function linkInBrowser(type) {
|
function linkInBrowser(type) {
|
||||||
let url;
|
let url;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'website':
|
case 'website':
|
||||||
url = "https://zulipchat.com";
|
url = "https://zulipchat.com";
|
||||||
break;
|
break;
|
||||||
case 'license':
|
case 'license':
|
||||||
url = "https://github.com/zulip/zulip-electron/blob/master/LICENSE";
|
url = "https://github.com/zulip/zulip-desktop/blob/master/LICENSE";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
shell.openExternal(url);
|
shell.openExternal(url);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>require('./js/shared/preventdrag.js')</script>
|
<script>require('./js/shared/preventdrag.js')</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
body {
|
body {
|
||||||
background: #fafafa;
|
background: rgba(250, 250, 250, 1.000);
|
||||||
font-family: menu, "Helvetica Neue", sans-serif;
|
font-family: menu, "Helvetica Neue", sans-serif;
|
||||||
-webkit-font-smoothing: subpixel-antialiased;
|
-webkit-font-smoothing: subpixel-antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
display: block;
|
display: block;
|
||||||
margin: -40px auto;
|
margin: -40px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#version {
|
#version {
|
||||||
color: #444343;
|
color: rgba(68, 67, 67, 1.000);
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about {
|
.about {
|
||||||
margin: 25vh auto;
|
margin: 25vh auto;
|
||||||
height: 25vh;
|
height: 25vh;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about p {
|
.about p {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
color: rgba(0, 0, 0, 0.62);
|
color: rgba(0, 0, 0, 0.62);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about img {
|
.about img {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail.maintainer {
|
.detail.maintainer {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail.license {
|
.detail.license {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.maintenance-info {
|
.maintenance-info {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
color: #444;
|
color: rgba(68, 68, 68, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.maintenance-info p {
|
.maintenance-info p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.detail a {
|
p.detail a {
|
||||||
color: #355f4c;
|
color: rgba(53, 95, 76, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.detail a:hover {
|
p.detail a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toggle-sidebar {
|
.toggle-sidebar {
|
||||||
background: #222c31;
|
background: rgba(34, 44, 49, 1.000);
|
||||||
width: 54px;
|
width: 54px;
|
||||||
padding: 27px 0 20px 0;
|
padding: 27px 0 20px 0;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -43,25 +43,25 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#view-controls-container {
|
#view-controls-container {
|
||||||
height: calc(100% - 208px);
|
height: calc(100% - 208px);
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#view-controls-container:hover {
|
#view-controls-container:hover {
|
||||||
overflow-y: overlay;
|
overflow-y: overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
#view-controls-container::-webkit-scrollbar {
|
#view-controls-container::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#view-controls-container::-webkit-scrollbar-track {
|
#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 {
|
#view-controls-container::-webkit-scrollbar-thumb {
|
||||||
background-color: darkgrey;
|
background-color: rgba(169, 169, 169, 1.000);
|
||||||
outline: 1px solid slategrey;
|
outline: 1px solid rgba(169, 169, 169, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@@ -119,12 +119,12 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-button i {
|
.action-button i {
|
||||||
color: #6c8592;
|
color: rgba(108, 133, 146, 1.000);
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button:hover i {
|
.action-button:hover i {
|
||||||
color: #98a9b3;
|
color: rgba(152, 169, 179, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button.disable {
|
.action-button.disable {
|
||||||
@@ -136,18 +136,18 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-button.disable:hover i {
|
.action-button.disable:hover i {
|
||||||
color: #6c8592;
|
color: rgba(108, 133, 146, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button.active {
|
.action-button.active {
|
||||||
/* background-color: rgba(255, 255, 255, 0.25); */
|
/* background-color: rgba(255, 255, 255, 0.25); */
|
||||||
background-color: #efefef;
|
background-color: rgba(239, 239, 239, 1.000);
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
padding-right: 14px;
|
padding-right: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button.active i {
|
.action-button.active i {
|
||||||
color: #1c262b;
|
color: rgba(28, 38, 43, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:first-child {
|
.tab:first-child {
|
||||||
@@ -177,7 +177,7 @@ body {
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
line-height: 31px;
|
line-height: 31px;
|
||||||
color: #eee;
|
color: rgba(238, 238, 238, 1.000);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
@@ -188,7 +188,7 @@ body {
|
|||||||
font-family: Verdana;
|
font-family: Verdana;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
border: 2px solid #222c31;
|
border: 2px solid rgba(34, 44, 49, 1.000);
|
||||||
margin-left: 17%;
|
margin-left: 17%;
|
||||||
width: 35px;
|
width: 35px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -216,7 +216,7 @@ body {
|
|||||||
|
|
||||||
.tab.active .server-tab {
|
.tab.active .server-tab {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background-color: #648478;
|
background-color: rgba(100, 132, 120, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab .server-tab-badge.active {
|
.tab .server-tab-badge.active {
|
||||||
@@ -224,7 +224,7 @@ body {
|
|||||||
min-width: 11px;
|
min-width: 11px;
|
||||||
padding: 0 3px;
|
padding: 0 3px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
background-color: #f44336;
|
background-color: rgba(244, 67, 54, 1.000);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -232,7 +232,7 @@ body {
|
|||||||
z-index: 15;
|
z-index: 15;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
float: right;
|
float: right;
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 17px;
|
line-height: 17px;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -260,7 +260,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tab .server-tab-shortcut {
|
.tab .server-tab-shortcut {
|
||||||
color: #648478;
|
color: rgba(100, 132, 120, 1.000);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@@ -278,19 +278,19 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Pseudo element for loading indicator*/
|
/* Pseudo element for loading indicator */
|
||||||
#webviews-container::before {
|
#webviews-container::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
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-size: 60px 60px;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*When the active webview is loaded*/
|
/* When the active webview is loaded */
|
||||||
#webviews-container.loaded::before {
|
#webviews-container.loaded::before {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
@@ -333,27 +333,27 @@ webview.focus {
|
|||||||
#reload-tooltip,
|
#reload-tooltip,
|
||||||
#setting-tooltip {
|
#setting-tooltip {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
background: #222c31;
|
background: rgba(34, 44, 49, 1.000);
|
||||||
margin-left: 48px;
|
margin-left: 48px;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
color: white;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 55px;
|
width: 55px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dnd-tooltip:after,
|
#dnd-tooltip::after,
|
||||||
#back-tooltip:after,
|
#back-tooltip::after,
|
||||||
#reload-tooltip:after,
|
#reload-tooltip::after,
|
||||||
#setting-tooltip:after {
|
#setting-tooltip::after {
|
||||||
content: " ";
|
content: " ";
|
||||||
border-top: 8px solid transparent;
|
border-top: 8px solid transparent;
|
||||||
border-bottom: 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;
|
position: absolute;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
right: 68px;
|
right: 68px;
|
||||||
@@ -362,25 +362,25 @@ webview.focus {
|
|||||||
#add-server-tooltip,
|
#add-server-tooltip,
|
||||||
.server-tooltip {
|
.server-tooltip {
|
||||||
font-family: 'arial';
|
font-family: 'arial';
|
||||||
background: #222c31;
|
background: rgba(34, 44, 49, 1.000);
|
||||||
left: 56px;
|
left: 56px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
margin-top: 11px;
|
margin-top: 11px;
|
||||||
z-index: 5000 !important;
|
z-index: 5000 !important;
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#add-server-tooltip:after,
|
#add-server-tooltip::after,
|
||||||
.server-tooltip:after {
|
.server-tooltip::after {
|
||||||
content: " ";
|
content: " ";
|
||||||
border-top: 8px solid transparent;
|
border-top: 8px solid transparent;
|
||||||
border-bottom: 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;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: -5px;
|
left: -5px;
|
||||||
@@ -392,14 +392,14 @@ webview.focus {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
background: #222c31;
|
background: rgba(34, 44, 49, 1.000);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: #999 1px 1px;
|
box-shadow: rgba(153, 153, 153, 1.000) 1px 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#collapse-button i {
|
#collapse-button i {
|
||||||
color: #efefef;
|
color: rgba(239, 239, 239, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-container {
|
#main-container {
|
||||||
@@ -420,8 +420,8 @@ webview.focus {
|
|||||||
|
|
||||||
.popup .popuptext {
|
.popup .popuptext {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
background-color: #555;
|
background-color: rgba(85, 85, 85, 1.000);
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 9px 0;
|
padding: 9px 0;
|
||||||
@@ -453,24 +453,24 @@ webview.focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
send-feedback {
|
send-feedback {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
height: 85%;
|
height: 85%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#feedback-modal {
|
#feedback-modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: rgba(68, 67, 67, 0.81);
|
background-color: rgba(68, 67, 67, 0.81);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: all 1s ease-out;
|
transition: all 1s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#feedback-modal.show {
|
#feedback-modal.show {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
html, body {
|
html,
|
||||||
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #333;
|
color: rgba(51, 51, 51, 1.000);
|
||||||
background: #fff;
|
background: rgba(255, 255, 255, 1.000);
|
||||||
user-select:none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content {
|
#content {
|
||||||
@@ -27,8 +28,8 @@ html, body {
|
|||||||
|
|
||||||
#reconnect {
|
#reconnect {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
background: #009688;
|
background: rgba(0, 150, 136, 1.000);
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
width: 84px;
|
width: 84px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|||||||
@@ -7,25 +7,25 @@ body {
|
|||||||
font-family: menu, "Helvetica Neue", sans-serif;
|
font-family: menu, "Helvetica Neue", sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
background: #efefef;
|
background: rgba(239, 239, 239, 1.000);
|
||||||
letter-spacing: -.08px;
|
letter-spacing: -.08px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
color: #8b8e8f;
|
color: rgba(139, 142, 143, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
kbd {
|
kbd {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid rgba(204, 204, 204, 1.000);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-family: Courier New, Courier, monospace;
|
font-family: Courier New, Courier, monospace;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background-color: #f7f7f7;
|
background-color: rgba(247, 247, 247, 1.000);
|
||||||
color: #333;
|
color: rgba(51, 51, 51, 1.000);
|
||||||
margin: 0 0.1em;
|
margin: 0 0.1em;
|
||||||
padding: 0.3em 0.8em;
|
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;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ table,
|
|||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
color: #383430;
|
color: rgba(56, 52, 48, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
@@ -43,11 +43,11 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
table tr:nth-child(even) {
|
table tr:nth-child(even) {
|
||||||
background-color: #fafafa;
|
background-color: rgba(250, 250, 250, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
table tr:nth-child(odd) {
|
table tr:nth-child(odd) {
|
||||||
background-color: #fff;
|
background-color: rgba(255, 255, 255, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -103,7 +103,7 @@ td:nth-child(odd) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
background: #f2f2f2;
|
background: rgba(242, 242, 242, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-container {
|
#nav-container {
|
||||||
@@ -112,18 +112,18 @@ td:nth-child(odd) {
|
|||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
padding: 7px 0;
|
padding: 7px 0;
|
||||||
color: #999;
|
color: rgba(153, 153, 153, 1.000);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav.active {
|
.nav.active {
|
||||||
color: #4ebfac;
|
color: rgba(78, 191, 172, 1.000);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav.active::before {
|
.nav.active::before {
|
||||||
background: #464e5a;
|
background: rgba(70, 78, 90, 1.000);
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -139,7 +139,7 @@ td:nth-child(odd) {
|
|||||||
|
|
||||||
#settings-header {
|
#settings-header {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
color: #222c31;
|
color: rgba(34, 44, 49, 1.000);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
@@ -159,11 +159,11 @@ td:nth-child(odd) {
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #222c31;
|
color: rgba(34, 44, 49, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
.page-title {
|
||||||
color: #222c31;
|
color: rgba(34, 44, 49, 1.000);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 4px 0 6px 0;
|
padding: 4px 0 6px 0;
|
||||||
@@ -182,7 +182,7 @@ td:nth-child(odd) {
|
|||||||
.sub-title {
|
.sub-title {
|
||||||
padding: 4px 0 6px 0;
|
padding: 4px 0 6px 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #616161;
|
color: rgba(97, 97, 97, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
img.server-info-icon {
|
img.server-info-icon {
|
||||||
@@ -249,14 +249,14 @@ img.server-info-icon {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 13px;
|
padding: 13px;
|
||||||
border: #ededed 2px solid;
|
border: rgba(237, 237, 237, 1.000) 2px solid;
|
||||||
outline-width: 0;
|
outline-width: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
max-width: 450px;
|
max-width: 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-input-value:focus {
|
.setting-input-value:focus {
|
||||||
border: #4EBFAC 2px solid;
|
border: rgba(78, 191, 172, 1.000) 2px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.manual-proxy-block {
|
.manual-proxy-block {
|
||||||
@@ -266,7 +266,7 @@ img.server-info-icon {
|
|||||||
.actions-container {
|
.actions-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #235d3a;
|
color: rgba(35, 93, 58, 1.000);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -287,6 +287,7 @@ img.server-info-icon {
|
|||||||
|
|
||||||
.settings-pane {
|
.settings-pane {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
min-width: 550px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action:hover {
|
.action:hover {
|
||||||
@@ -298,7 +299,7 @@ img.server-info-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action.disabled {
|
.action.disabled {
|
||||||
color: #999;
|
color: rgba(153, 153, 153, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-card {
|
.settings-card {
|
||||||
@@ -306,7 +307,7 @@ img.server-info-icon {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 12px 30px;
|
padding: 12px 30px;
|
||||||
margin: 10px 0 20px 0;
|
margin: 10px 0 20px 0;
|
||||||
background: #fff;
|
background: rgba(255, 255, 255, 1.000);
|
||||||
width: 80%;
|
width: 80%;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
@@ -321,21 +322,29 @@ img.server-info-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.red {
|
.red {
|
||||||
color: #ef5350;
|
color: rgb(240, 148, 148);
|
||||||
padding: 8px;
|
background: rgba(255, 255, 255, 1.000);
|
||||||
border: rgba(239, 83, 80, 0.5) solid 1px;
|
|
||||||
border-radius: 4px;
|
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 {
|
.red:hover {
|
||||||
background-color: rgba(230, 52, 49, 0.5);
|
background-color: rgb(240, 148, 148);
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.green {
|
.green {
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
background: #4EBFAC;
|
background: rgba(78, 191, 172, 1.000);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -350,8 +359,8 @@ img.server-info-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.green:hover {
|
.green:hover {
|
||||||
background-color: #3c9f8d;
|
background-color: rgba(60, 159, 141, 1.000);
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-150 {
|
.w-150 {
|
||||||
@@ -363,9 +372,9 @@ img.server-info-icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grey {
|
.grey {
|
||||||
color: #9E9E9E;
|
color: rgba(158, 158, 158, 1.000);
|
||||||
background: #FAFAFA;
|
background: rgba(250, 250, 250, 1.000);
|
||||||
border: 1px solid #9E9E9E;
|
border: 1px solid rgba(158, 158, 158, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-row {
|
.setting-row {
|
||||||
@@ -392,7 +401,7 @@ i.open-tab-button {
|
|||||||
|
|
||||||
.selected-css-path,
|
.selected-css-path,
|
||||||
.download-folder-path {
|
.download-folder-path {
|
||||||
background: #eeeeee;
|
background: rgba(238, 238, 238, 1.000);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -432,7 +441,7 @@ i.open-tab-button {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle+label {
|
.toggle + label {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -440,16 +449,16 @@ i.open-tab-button {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round+label {
|
input.toggle-round + label {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
background-color: #dddddd;
|
background-color: rgba(221, 221, 221, 1.000);
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round+label:before,
|
input.toggle-round + label::before,
|
||||||
input.toggle-round+label:after {
|
input.toggle-round + label::after {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
@@ -458,8 +467,8 @@ input.toggle-round+label:after {
|
|||||||
content: "";
|
content: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round+label:before {
|
input.toggle-round + label::before {
|
||||||
background-color: #f1f1f1;
|
background-color: rgba(241, 241, 241, 1.000);
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
@@ -467,22 +476,22 @@ input.toggle-round+label:before {
|
|||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round+label:after {
|
input.toggle-round + label::after {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
background-color: #fff;
|
background-color: rgba(255, 255, 255, 1.000);
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round:checked+label:before {
|
input.toggle-round:checked + label::before {
|
||||||
background-color: #4EBFAC;
|
background-color: rgba(78, 191, 172, 1.000);
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.toggle-round:checked+label:after {
|
input.toggle-round:checked + label::after {
|
||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,17 +508,17 @@ input.toggle-round:checked+label:after {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* background: rgba(61, 64, 67, 15); */
|
/* 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;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal Content */
|
/* Modal Content */
|
||||||
|
|
||||||
.modal-container {
|
.modal-container {
|
||||||
background-color: #f4f7f8;
|
background-color: rgba(244, 247, 248, 1.000);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 57px;
|
padding: 57px;
|
||||||
border: #dae1e3 1px solid;
|
border: rgba(218, 225, 227, 1.000) 1px solid;
|
||||||
width: 550px;
|
width: 550px;
|
||||||
height: 370px;
|
height: 370px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -523,7 +532,7 @@ input.toggle-round:checked+label:after {
|
|||||||
.divider {
|
.divider {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
color: #7d878a;
|
color: rgba(125, 135, 138, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider hr {
|
.divider hr {
|
||||||
@@ -554,8 +563,8 @@ input.toggle-round:checked+label:after {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #fff;
|
color: rgba(255, 255, 255, 1.000);
|
||||||
background: #4EBFAC;
|
background: rgba(78, 191, 172, 1.000);
|
||||||
border-color: none;
|
border-color: none;
|
||||||
border: none;
|
border: none;
|
||||||
width: 98%;
|
width: 98%;
|
||||||
@@ -565,15 +574,15 @@ input.toggle-round:checked+label:after {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.server-center button:hover {
|
.server-center button:hover {
|
||||||
background: #329588;
|
background: rgba(50, 149, 136, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-center button:focus {
|
.server-center button:focus {
|
||||||
background: #329588;
|
background: rgba(50, 149, 136, 1.000);
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificates-card {
|
.certificates-card {
|
||||||
width: 80%
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-input {
|
.certificate-input {
|
||||||
@@ -600,8 +609,8 @@ input.toggle-round:checked+label:after {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip:hover{
|
.tip:hover {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.md-14 {
|
.md-14 {
|
||||||
@@ -676,4 +685,4 @@ input.toggle-round:checked+label:after {
|
|||||||
.action {
|
.action {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* Override css rules */
|
/* Override css rules */
|
||||||
|
|
||||||
.portico-wrap>.header {
|
.portico-wrap > .header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.portico-container>.footer {
|
.portico-container > .footer {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -95,6 +95,11 @@ class WebView extends BaseComponent {
|
|||||||
}
|
}
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.show();
|
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 => {
|
this.$el.addEventListener('did-fail-load', event => {
|
||||||
@@ -165,7 +170,13 @@ class WebView extends BaseComponent {
|
|||||||
focus() {
|
focus() {
|
||||||
// focus Webview and it's contents when Window regain focus.
|
// focus Webview and it's contents when Window regain focus.
|
||||||
const webContents = this.$el.getWebContents();
|
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();
|
this.$el.focus();
|
||||||
webContents.focus();
|
webContents.focus();
|
||||||
}
|
}
|
||||||
@@ -214,6 +225,7 @@ class WebView extends BaseComponent {
|
|||||||
back() {
|
back() {
|
||||||
if (this.$el.canGoBack()) {
|
if (this.$el.canGoBack()) {
|
||||||
this.$el.goBack();
|
this.$el.goBack();
|
||||||
|
this.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { ipcRenderer, remote } = require('electron');
|
const { ipcRenderer, remote, clipboard } = require('electron');
|
||||||
const isDev = require('electron-is-dev');
|
const isDev = require('electron-is-dev');
|
||||||
|
|
||||||
const { session, app, Menu, dialog } = remote;
|
const { session, app, Menu, dialog } = remote;
|
||||||
@@ -105,12 +105,13 @@ class ServerManagerView {
|
|||||||
useSystemProxy: false,
|
useSystemProxy: false,
|
||||||
showSidebar: true,
|
showSidebar: true,
|
||||||
badgeOption: true,
|
badgeOption: true,
|
||||||
startAtLogin: false,
|
startAtLogin: true,
|
||||||
startMinimized: false,
|
startMinimized: false,
|
||||||
enableSpellchecker: true,
|
enableSpellchecker: true,
|
||||||
showNotification: true,
|
showNotification: true,
|
||||||
autoUpdate: true,
|
autoUpdate: true,
|
||||||
betaUpdate: false,
|
betaUpdate: false,
|
||||||
|
errorReporting: true,
|
||||||
customCSS: false,
|
customCSS: false,
|
||||||
silent: false,
|
silent: false,
|
||||||
lastActiveTab: 0,
|
lastActiveTab: 0,
|
||||||
@@ -186,6 +187,7 @@ class ServerManagerView {
|
|||||||
index,
|
index,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
role: 'server',
|
||||||
name: CommonUtil.decodeString(server.alias),
|
name: CommonUtil.decodeString(server.alias),
|
||||||
isActive: () => {
|
isActive: () => {
|
||||||
return index === this.activeTabIndex;
|
return index === this.activeTabIndex;
|
||||||
@@ -337,6 +339,7 @@ class ServerManagerView {
|
|||||||
index: this.functionalTabs[tabProps.name],
|
index: this.functionalTabs[tabProps.name],
|
||||||
tabIndex,
|
tabIndex,
|
||||||
url: tabProps.url,
|
url: tabProps.url,
|
||||||
|
role: 'function',
|
||||||
name: tabProps.name,
|
name: tabProps.name,
|
||||||
isActive: () => {
|
isActive: () => {
|
||||||
return this.functionalTabs[tabProps.name] === this.activeTabIndex;
|
return this.functionalTabs[tabProps.name] === this.activeTabIndex;
|
||||||
@@ -512,7 +515,7 @@ class ServerManagerView {
|
|||||||
|
|
||||||
// Toggles the dnd button icon.
|
// Toggles the dnd button icon.
|
||||||
toggleDNDButton(alert) {
|
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';
|
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);
|
const contextMenu = Menu.buildFromTemplate(template);
|
||||||
@@ -724,6 +733,14 @@ class ServerManagerView {
|
|||||||
ipcRenderer.on('open-feedback-modal', () => {
|
ipcRenderer.on('open-feedback-modal', () => {
|
||||||
feedbackHolder.classList.add('show');
|
feedbackHolder.classList.add('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('copy-zulip-url', () => {
|
||||||
|
clipboard.writeText(DomainUtil.getDomain(this.activeTabIndex).url);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('new-server', () => {
|
||||||
|
this.openSettings('AddServer');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class GeneralSection extends BaseSection {
|
|||||||
<div class="setting-control"></div>
|
<div class="setting-control"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row" id="menubar-option" style= "display:${process.platform === 'darwin' ? 'none' : ''}">
|
<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 class="setting-control"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row" id="sidebar-option">
|
<div class="setting-row" id="sidebar-option">
|
||||||
@@ -47,7 +47,7 @@ class GeneralSection extends BaseSection {
|
|||||||
<div class="title">Desktop Notifications</div>
|
<div class="title">Desktop Notifications</div>
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<div class="setting-row" id="show-notification-option">
|
<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 class="setting-control"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-row" id="silent-option">
|
<div class="setting-row" id="silent-option">
|
||||||
@@ -83,6 +83,10 @@ class GeneralSection extends BaseSection {
|
|||||||
</div>
|
</div>
|
||||||
<div class="title">Advanced</div>
|
<div class="title">Advanced</div>
|
||||||
<div class="settings-card">
|
<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-row" id="show-download-folder">
|
||||||
<div class="setting-description">Show downloaded files in file manager</div>
|
<div class="setting-description">Show downloaded files in file manager</div>
|
||||||
<div class="setting-control"></div>
|
<div class="setting-control"></div>
|
||||||
@@ -120,7 +124,7 @@ class GeneralSection extends BaseSection {
|
|||||||
<div class="setting-row" id="resetdata-option">
|
<div class="setting-row" id="resetdata-option">
|
||||||
<div class="setting-description">This will delete all application data including all added accounts and preferences
|
<div class="setting-description">This will delete all application data including all added accounts and preferences
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,6 +149,7 @@ class GeneralSection extends BaseSection {
|
|||||||
this.removeCustomCSS();
|
this.removeCustomCSS();
|
||||||
this.downloadFolder();
|
this.downloadFolder();
|
||||||
this.showDownloadFolder();
|
this.showDownloadFolder();
|
||||||
|
this.enableErrorReporting();
|
||||||
|
|
||||||
// Platform specific settings
|
// 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() {
|
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 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());
|
const getAppPath = path.join(app.getPath('appData'), app.getName());
|
||||||
|
|||||||
@@ -130,6 +130,14 @@ class ShortcutsSection extends BaseSection {
|
|||||||
<td><kbd>Option</kbd><kbd>${userOSKey}</kbd><kbd>U</kbd></td>
|
<td><kbd>Option</kbd><kbd>${userOSKey}</kbd><kbd>U</kbd></td>
|
||||||
<td>Toggle DevTools for Active Tab</td>
|
<td>Toggle DevTools for Active Tab</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
<div class="setting-control"></div>
|
<div class="setting-control"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,6 +178,7 @@ class ShortcutsSection extends BaseSection {
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="settings-pane">
|
<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="title">Application Shortcuts</div>
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<table>
|
<table>
|
||||||
@@ -269,6 +278,14 @@ class ShortcutsSection extends BaseSection {
|
|||||||
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd></td>
|
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>U</kbd></td>
|
||||||
<td>Toggle DevTools for Active Tab</td>
|
<td>Toggle DevTools for Active Tab</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
<div class="setting-control"></div>
|
<div class="setting-control"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -300,7 +317,6 @@ class ShortcutsSection extends BaseSection {
|
|||||||
</table>
|
</table>
|
||||||
<div class="setting-control"></div>
|
<div class="setting-control"></div>
|
||||||
</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>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,15 @@ window.addEventListener('beforeunload', () => {
|
|||||||
|
|
||||||
// electron's globalShortcut can cause unexpected results
|
// electron's globalShortcut can cause unexpected results
|
||||||
// so adding the reload shortcut in the old-school way
|
// 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 => {
|
document.addEventListener('keydown', event => {
|
||||||
if (event.code === 'F5') {
|
if (event.code === 'F5') {
|
||||||
ipcRenderer.send('forward-message', 'hard-reload');
|
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');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,14 +32,7 @@ class SetupSpellChecker {
|
|||||||
|
|
||||||
const userLanguage = ConfigUtil.getConfigItem('spellcheckerLanguage');
|
const userLanguage = ConfigUtil.getConfigItem('spellcheckerLanguage');
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
this.SpellCheckHandler.switchLanguage(userLanguage);
|
||||||
process.platform === 'darwin' ?
|
|
||||||
// On macOS, spellchecker fails to auto-detect the lanugage user is typing in
|
|
||||||
// that's why we need to mention it explicitly
|
|
||||||
this.SpellCheckHandler.switchLanguage(userLanguage) :
|
|
||||||
// On Linux and Windows, spellchecker can automatically detects the language the user is typing in
|
|
||||||
// and silently switches on the fly; thus we can start off as US English
|
|
||||||
this.SpellCheckHandler.switchLanguage('en-US');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const contextMenuBuilder = new ContextMenuBuilder(this.SpellCheckHandler);
|
const contextMenuBuilder = new ContextMenuBuilder(this.SpellCheckHandler);
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ const escape = require('escape-html');
|
|||||||
|
|
||||||
const Logger = require('./logger-util');
|
const Logger = require('./logger-util');
|
||||||
|
|
||||||
const CertificateUtil = require(__dirname + '/certificate-util.js');
|
const RequestUtil = require(__dirname + '/../utils/request-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({
|
const logger = new Logger({
|
||||||
file: `domain-util.log`,
|
file: `domain-util.log`,
|
||||||
@@ -64,9 +61,10 @@ class DomainUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addDomain(server) {
|
addDomain(server) {
|
||||||
|
const ignoreCerts = server.ignoreCerts;
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (server.icon) {
|
if (server.icon) {
|
||||||
this.saveServerIcon(server).then(localIconUrl => {
|
this.saveServerIcon(server, ignoreCerts).then(localIconUrl => {
|
||||||
server.icon = localIconUrl;
|
server.icon = localIconUrl;
|
||||||
this.db.push('/domains[]', server, true);
|
this.db.push('/domains[]', server, true);
|
||||||
this.reloadDB();
|
this.reloadDB();
|
||||||
@@ -103,42 +101,25 @@ class DomainUtil {
|
|||||||
return false;
|
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)) {
|
if (!silent && this.duplicateDomain(domain)) {
|
||||||
// Do not check duplicate in silent mode
|
// Do not check duplicate in silent mode
|
||||||
return Promise.reject('This server has been added.');
|
return Promise.reject('This server has been added.');
|
||||||
}
|
}
|
||||||
|
|
||||||
domain = this.formatUrl(domain);
|
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 = {
|
const checkDomain = {
|
||||||
url: domain + '/static/audio/zulip.ogg',
|
url: domain + '/static/audio/zulip.ogg',
|
||||||
ca: (certificateLocation) ? certificateLocation : '',
|
...RequestUtil.requestOptions(domain, ignoreCerts)
|
||||||
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : '',
|
|
||||||
ecdhCurve: 'auto',
|
|
||||||
headers: { 'User-Agent': SystemUtil.getUserAgent() }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const serverConf = {
|
const serverConf = {
|
||||||
icon: defaultIconUrl,
|
icon: defaultIconUrl,
|
||||||
url: domain,
|
url: domain,
|
||||||
alias: domain
|
alias: domain,
|
||||||
|
ignoreCerts
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -155,14 +136,14 @@ class DomainUtil {
|
|||||||
const certsError = error.toString().includes('certificate');
|
const certsError = error.toString().includes('certificate');
|
||||||
if (!error && response.statusCode < 400) {
|
if (!error && response.statusCode < 400) {
|
||||||
// Correct
|
// Correct
|
||||||
this.getServerSettings(domain).then(serverSettings => {
|
this.getServerSettings(domain, serverConf.ignoreCerts).then(serverSettings => {
|
||||||
resolve(serverSettings);
|
resolve(serverSettings);
|
||||||
}, () => {
|
}, () => {
|
||||||
resolve(serverConf);
|
resolve(serverConf);
|
||||||
});
|
});
|
||||||
} else if (domain.indexOf(whitelistDomains) >= 0 || certsError) {
|
} else if (domain.indexOf(whitelistDomains) >= 0 || certsError) {
|
||||||
if (silent) {
|
if (silent) {
|
||||||
this.getServerSettings(domain).then(serverSettings => {
|
this.getServerSettings(domain, serverConf.ignoreCerts).then(serverSettings => {
|
||||||
resolve(serverSettings);
|
resolve(serverSettings);
|
||||||
}, () => {
|
}, () => {
|
||||||
resolve(serverConf);
|
resolve(serverConf);
|
||||||
@@ -185,7 +166,9 @@ class DomainUtil {
|
|||||||
detail: certErrorDetail
|
detail: certErrorDetail
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response === 0) {
|
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(serverSettings);
|
||||||
}, () => {
|
}, () => {
|
||||||
resolve(serverConf);
|
resolve(serverConf);
|
||||||
@@ -205,27 +188,12 @@ class DomainUtil {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getServerSettings(domain) {
|
getServerSettings(domain, ignoreCerts = false) {
|
||||||
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');
|
|
||||||
const serverSettingsOptions = {
|
const serverSettingsOptions = {
|
||||||
url: domain + '/api/v1/server_settings',
|
url: domain + '/api/v1/server_settings',
|
||||||
ca: (certificateLocation) ? certificateLocation : '',
|
...RequestUtil.requestOptions(domain, ignoreCerts)
|
||||||
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : '',
|
|
||||||
ecdhCurve: 'auto',
|
|
||||||
headers: { 'User-Agent': SystemUtil.getUserAgent() }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
request(serverSettingsOptions, (error, response) => {
|
request(serverSettingsOptions, (error, response) => {
|
||||||
if (!error && response.statusCode === 200) {
|
if (!error && response.statusCode === 200) {
|
||||||
@@ -236,7 +204,8 @@ class DomainUtil {
|
|||||||
// Following check handles both the cases
|
// Following check handles both the cases
|
||||||
icon: data.realm_icon.startsWith('/') ? data.realm_uri + data.realm_icon : data.realm_icon,
|
icon: data.realm_icon.startsWith('/') ? data.realm_uri + data.realm_icon : data.realm_icon,
|
||||||
url: data.realm_uri,
|
url: data.realm_uri,
|
||||||
alias: escape(data.realm_name)
|
alias: escape(data.realm_name),
|
||||||
|
ignoreCerts
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -246,31 +215,13 @@ class DomainUtil {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
saveServerIcon(server) {
|
saveServerIcon(server, ignoreCerts = false) {
|
||||||
const url = server.icon;
|
const url = server.icon;
|
||||||
const domain = server.url;
|
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 = {
|
const serverIconOptions = {
|
||||||
url,
|
url,
|
||||||
ca: (certificateLocation) ? certificateLocation : '',
|
...RequestUtil.requestOptions(domain, ignoreCerts)
|
||||||
proxy: proxyEnabled ? ProxyUtil.getProxy(url) : '',
|
|
||||||
ecdhCurve: 'auto',
|
|
||||||
headers: { 'User-Agent': SystemUtil.getUserAgent() }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The save will always succeed. If url is invalid, downgrade to default icon.
|
// The save will always succeed. If url is invalid, downgrade to default icon.
|
||||||
@@ -305,8 +256,9 @@ class DomainUtil {
|
|||||||
|
|
||||||
updateSavedServer(url, index) {
|
updateSavedServer(url, index) {
|
||||||
// Does not promise successful update
|
// Does not promise successful update
|
||||||
this.checkDomain(url, true).then(newServerConf => {
|
const ignoreCerts = this.getDomain(index).ignoreCerts;
|
||||||
this.saveServerIcon(newServerConf).then(localIconUrl => {
|
this.checkDomain(url, ignoreCerts, true).then(newServerConf => {
|
||||||
|
this.saveServerIcon(newServerConf, ignoreCerts).then(localIconUrl => {
|
||||||
newServerConf.icon = localIconUrl;
|
newServerConf.icon = localIconUrl;
|
||||||
this.updateDomain(index, newServerConf);
|
this.updateDomain(index, newServerConf);
|
||||||
this.reloadDB();
|
this.reloadDB();
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
const NodeConsole = require('console').Console;
|
const NodeConsole = require('console').Console;
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const isDev = require('electron-is-dev');
|
const isDev = require('electron-is-dev');
|
||||||
const { initSetUp } = require('./default-util');
|
const { initSetUp } = require('./default-util');
|
||||||
const { sentryInit, captureException } = require('./sentry-util');
|
const { sentryInit, captureException } = require('./sentry-util');
|
||||||
|
|
||||||
initSetUp();
|
initSetUp();
|
||||||
sentryInit();
|
|
||||||
let app = null;
|
let app = null;
|
||||||
|
let reportErrors = true;
|
||||||
if (process.type === 'renderer') {
|
if (process.type === 'renderer') {
|
||||||
app = require('electron').remote.app;
|
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 {
|
} else {
|
||||||
app = require('electron').app;
|
app = require('electron').app;
|
||||||
}
|
}
|
||||||
@@ -30,6 +44,13 @@ class Logger {
|
|||||||
timestamp = this.getTimestamp;
|
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 fileStream = fs.createWriteStream(file, { flags: 'a' });
|
||||||
const nodeConsole = new NodeConsole(fileStream);
|
const nodeConsole = new NodeConsole(fileStream);
|
||||||
|
|
||||||
@@ -86,7 +107,27 @@ class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reportSentry(err) {
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class ProxyUtil {
|
|||||||
resolveSystemProxy(mainWindow) {
|
resolveSystemProxy(mainWindow) {
|
||||||
const page = mainWindow.webContents;
|
const page = mainWindow.webContents;
|
||||||
const ses = page.session;
|
const ses = page.session;
|
||||||
const resolveProxyUrl = 'www.google.com';
|
const resolveProxyUrl = 'www.example.com';
|
||||||
|
|
||||||
// Check HTTP Proxy
|
// Check HTTP Proxy
|
||||||
const httpProxy = new Promise(resolve => {
|
const httpProxy = new Promise(resolve => {
|
||||||
|
|||||||
62
app/renderer/js/utils/request-util.js
Normal file
62
app/renderer/js/utils/request-util.js
Normal 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();
|
||||||
@@ -1,56 +1,56 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="responsive desktop">
|
<html lang="en" class="responsive desktop">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>Zulip</title>
|
<title>Zulip</title>
|
||||||
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
|
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div class="popup">
|
<div class="popup">
|
||||||
<span class="popuptext hidden" id="fullscreen-popup"></span>
|
<span class="popuptext hidden" id="fullscreen-popup"></span>
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebar" class="toggle-sidebar">
|
<div id="sidebar" class="toggle-sidebar">
|
||||||
<div id="view-controls-container">
|
<div id="view-controls-container">
|
||||||
<div id="tabs-container"></div>
|
<div id="tabs-container"></div>
|
||||||
<div id="add-tab" class="tab functional-tab">
|
<div id="add-tab" class="tab functional-tab">
|
||||||
<div class="server-tab" id="add-action">
|
<div class="server-tab" id="add-action">
|
||||||
<i class="material-icons">add</i>
|
<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>
|
</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">
|
<div id="feedback-modal">
|
||||||
<send-feedback></send-feedback>
|
<send-feedback></send-feedback>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="js/main.js"></script>
|
<script src="js/main.js"></script>
|
||||||
<script>require('./js/shared/preventdrag.js')</script>
|
<script>require('./js/shared/preventdrag.js')</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="responsive desktop">
|
<html lang="en" class="responsive desktop">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>Zulip - Network Troubleshooting</title>
|
<title>Zulip - Network Troubleshooting</title>
|
||||||
<link rel="stylesheet" href="css/network.css" type="text/css" media="screen">
|
<link rel="stylesheet" href="css/network.css" type="text/css" media="screen">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div id="picture"><img src="img/zulip_network.png"></div>
|
<div id="picture"><img src="img/zulip_network.png"></div>
|
||||||
<div id="title">Zulip can't connect</div>
|
<div id="title">Zulip can't connect</div>
|
||||||
<div id="description">
|
<div id="description">
|
||||||
<div>Your computer seems to be offline.</div>
|
<div>Your computer seems to be offline.</div>
|
||||||
<div>We will keep trying to reconnect, or you can try now.</div>
|
<div>We will keep trying to reconnect, or you can try now.</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="reconnect">Try now</div>
|
<div id="reconnect">Try now</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="js/pages/network.js"></script>
|
<script src="js/pages/network.js"></script>
|
||||||
<script>require('./js/shared/preventdrag.js')</script>
|
<script>require('./js/shared/preventdrag.js')</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="responsive desktop">
|
<html lang="en" class="responsive desktop">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>Zulip - Settings</title>
|
<title>Zulip - Settings</title>
|
||||||
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
|
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div id="sidebar"></div>
|
<div id="sidebar"></div>
|
||||||
<div id="settings-container"></div>
|
<div id="settings-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="js/pages/preference/preference.js"></script>
|
<script src="js/pages/preference/preference.js"></script>
|
||||||
<script>require('./js/shared/preventdrag.js')</script>
|
<script>require('./js/shared/preventdrag.js')</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
BIN
build/icon.png
BIN
build/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
20
changelog.md
20
changelog.md
@@ -292,7 +292,7 @@ electron-updater - `v2.21.8`
|
|||||||
|
|
||||||
* Setting page and left-sidebar UI improvements
|
* 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
|
* 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
|
* Handle certificate issue properly
|
||||||
|
|
||||||
@@ -620,7 +620,7 @@ electron-updater - `v2.21.8`
|
|||||||
|
|
||||||
* Properly signed app for macOS
|
* Properly signed app for macOS
|
||||||
* Toggle tray icon
|
* 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
|
### v0.5.8 --2017-02-13
|
||||||
|
|
||||||
**Enhacements**:
|
**Enhancements**:
|
||||||
Smaller Windows installer size
|
Smaller Windows installer size
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@@ -650,7 +650,7 @@ Minor improvements
|
|||||||
### v0.5.6 --2017-02-07
|
### v0.5.6 --2017-02-07
|
||||||
|
|
||||||
|
|
||||||
**Enhacements**:
|
**Enhancement**:
|
||||||
|
|
||||||
- Using NSIS instead of [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows) on Windows
|
- Using NSIS instead of [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows) on Windows
|
||||||
|
|
||||||
@@ -672,9 +672,9 @@ Minor improvements
|
|||||||
|
|
||||||
**Fixes**:
|
**Fixes**:
|
||||||
- Fixed :
|
- Fixed :
|
||||||
- Auto-updates
|
- Auto-updates
|
||||||
- Spellchecker
|
- Spellchecker
|
||||||
- Zooming functionality
|
- Zooming functionality
|
||||||
|
|
||||||
- Removed unused node modules
|
- Removed unused node modules
|
||||||
- Using stable version for node modules
|
- Using stable version for node modules
|
||||||
@@ -718,7 +718,7 @@ Minor improvements
|
|||||||
|
|
||||||
### v0.5.1 --2016-11-23
|
### v0.5.1 --2016-11-23
|
||||||
|
|
||||||
**Enhacements**:
|
**Enhancement**:
|
||||||
|
|
||||||
- Added Spellchecker support with correct spell suggestions
|
- Added Spellchecker support with correct spell suggestions
|
||||||
|
|
||||||
@@ -759,6 +759,6 @@ Minor improvements
|
|||||||
|
|
||||||
### v0.0.1-alpha -- 2016-08-31
|
### v0.0.1-alpha -- 2016-08-31
|
||||||
|
|
||||||
**Enhacements**:
|
**Enhancement**:
|
||||||
|
|
||||||
* Added DMG installer for macOS
|
* Added DMG installer for macOS
|
||||||
|
|||||||
191
development.md
191
development.md
@@ -1,85 +1,152 @@
|
|||||||
|
# Improve development guide
|
||||||
|
|
||||||
# Development setup
|
# Development setup
|
||||||
|
|
||||||
This is a guide to running the Zulip desktop app from a source tree,
|
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). You’ll 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.**
|
||||||
in order to contribute to developing it.
|
|
||||||
|
|
||||||
## 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)
|
Follow our [Git Guide](https://zulip.readthedocs.io/en/latest/git/setup.html) in order to install Git, set up a GitHub account
|
||||||
* [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
|
|
||||||
|
|
||||||
### Debian/Ubuntu and friends
|
|
||||||
|
|
||||||
On a system running Debian, Ubuntu, or another Debian-based Linux
|
# Install Prerequisites
|
||||||
distribution, you can install all dependencies through the package
|
|
||||||
manager (see [here][nodesource-install] for more on the first command):
|
|
||||||
|
|
||||||
```sh
|
Jump to:
|
||||||
$ 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
|
|
||||||
```
|
|
||||||
|
|
||||||
[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.
|
## MacOS
|
||||||
PRs to add specific instructions to this doc are welcome!
|
|
||||||
|
|
||||||
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:
|
**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**
|
||||||
```sh
|
|
||||||
$ npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
Start the app:
|
|
||||||
```sh
|
|
||||||
$ npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
Start and watch changes:
|
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)
|
||||||
```sh
|
|
||||||
$ npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If you have any problems running the app, see the [most common
|
## Ubuntu/Debian
|
||||||
issues](./troubleshooting.md).
|
|
||||||
|
|
||||||
## Making a release
|
|
||||||
|
|
||||||
To package the app into an installer:
|
If you’re in a hurry, you can copy and paste the following into your terminal
|
||||||
```
|
|
||||||
npm run dist
|
|
||||||
```
|
|
||||||
|
|
||||||
This command will produce distributable packages or installers for the
|
sudo apt install git nodejs node-gyp python build-essential snapcraft libxext-dev libxtst-dev lib xkbfile-dev libgconf-2-4
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
Don’t 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 dev’s**
|
||||||
|
|
||||||
|
$ npm run dev
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ C:\Windows\system32> npm install --global --production windows-build-tools
|
|||||||
Clone the source locally:
|
Clone the source locally:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ git clone https://github.com/zulip/zulip-electron
|
$ git clone https://github.com/zulip/zulip-desktop
|
||||||
$ cd zulip-electron
|
$ cd zulip-desktop
|
||||||
```
|
```
|
||||||
|
|
||||||
Install project dependencies:
|
Install project dependencies:
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
### Want to contribute to this Wiki?
|
### 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)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# How to install
|
# 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.
|
- **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.
|
- **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
|
## OS X
|
||||||
|
|
||||||
|
|||||||
2965
package-lock.json
generated
2965
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"productName": "Zulip",
|
"productName": "Zulip",
|
||||||
"version": "2.4.0",
|
"version": "3.0.0",
|
||||||
"main": "./app/main",
|
"main": "./app/main",
|
||||||
"description": "Zulip Desktop App",
|
"description": "Zulip Desktop App",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/zulip/zulip-electron.git"
|
"url": "https://github.com/zulip/zulip-desktop.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/zulip/zulip-electron/issues"
|
"url": "https://github.com/zulip/zulip-desktop/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@@ -24,7 +24,10 @@
|
|||||||
"start": "electron app --disable-http-cache --no-electron-connect",
|
"start": "electron app --disable-http-cache --no-electron-connect",
|
||||||
"reinstall": "node ./tools/reinstall-node-modules.js",
|
"reinstall": "node ./tools/reinstall-node-modules.js",
|
||||||
"postinstall": "electron-builder install-app-deps",
|
"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",
|
"test-e2e": "gulp test-e2e",
|
||||||
"dev": "gulp dev & nodemon --watch app/main --watch app/renderer --exec 'npm test' -e html,css,js",
|
"dev": "gulp dev & nodemon --watch app/main --watch app/renderer --exec 'npm test' -e html,css,js",
|
||||||
"pack": "electron-builder --dir",
|
"pack": "electron-builder --dir",
|
||||||
@@ -44,7 +47,7 @@
|
|||||||
"!docs${/*}",
|
"!docs${/*}",
|
||||||
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
|
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
|
||||||
],
|
],
|
||||||
"copyright": "©2017 Kandra Labs, Inc.",
|
"copyright": "©2019 Kandra Labs, Inc.",
|
||||||
"mac": {
|
"mac": {
|
||||||
"category": "public.app-category.productivity",
|
"category": "public.app-category.productivity",
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
||||||
@@ -59,7 +62,7 @@
|
|||||||
"AppImage",
|
"AppImage",
|
||||||
"snap"
|
"snap"
|
||||||
],
|
],
|
||||||
"maintainer": "Akash Nimare <svnitakash@gmail.com>",
|
"maintainer": "Akash Nimare <akash@zulipchat.com>",
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
||||||
},
|
},
|
||||||
"deb": {
|
"deb": {
|
||||||
@@ -103,10 +106,13 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "build/icon.ico",
|
"icon": "build/icon.ico",
|
||||||
|
"artifactName": "${productName}-Web-Setup-${version}.${ext}",
|
||||||
"publisherName": "Kandra Labs, Inc."
|
"publisherName": "Kandra Labs, Inc."
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"allowToChangeInstallationDirectory": true
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"oneClick": false,
|
||||||
|
"perMachine": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -119,21 +125,23 @@
|
|||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"assert": "1.4.1",
|
"assert": "1.4.1",
|
||||||
"cp-file": "^5.0.0",
|
"cp-file": "5.0.0",
|
||||||
"devtron": "1.4.0",
|
"devtron": "1.4.0",
|
||||||
"electron": "3.0.10",
|
"electron": "3.0.10",
|
||||||
"electron-builder": "20.38.4",
|
"electron-builder": "20.40.2",
|
||||||
"electron-connect": "0.6.2",
|
"electron-connect": "0.6.2",
|
||||||
"electron-debug": "1.4.0",
|
"electron-debug": "1.4.0",
|
||||||
"google-translate-api": "2.3.0",
|
"google-translate-api": "2.3.0",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "4.0.0",
|
||||||
"gulp-tape": "0.0.9",
|
"gulp-tape": "0.0.9",
|
||||||
"is-ci": "^1.0.10",
|
"htmlhint": "0.11.0",
|
||||||
"nodemon": "^1.14.11",
|
"is-ci": "1.0.10",
|
||||||
|
"nodemon": "1.14.11",
|
||||||
"pre-commit": "1.2.2",
|
"pre-commit": "1.2.2",
|
||||||
"spectron": "^5.0.0",
|
"spectron": "5.0.0",
|
||||||
"tap-colorize": "^1.2.0",
|
"stylelint": "9.10.1",
|
||||||
"tape": "^4.8.0",
|
"tap-colorize": "1.2.0",
|
||||||
|
"tape": "4.8.0",
|
||||||
"xo": "0.18.2"
|
"xo": "0.18.2"
|
||||||
},
|
},
|
||||||
"xo": {
|
"xo": {
|
||||||
@@ -151,7 +159,7 @@
|
|||||||
"max-lines": [
|
"max-lines": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
"max": 600,
|
"max": 700,
|
||||||
"skipBlankLines": true,
|
"skipBlankLines": true,
|
||||||
"skipComments": true
|
"skipComments": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: zulip
|
name: zulip
|
||||||
version: 2.0.0
|
version: 2.3.82
|
||||||
summary: Zulip Desktop Client for Linux
|
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.
|
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
|
confinement: strict
|
||||||
@@ -34,4 +34,4 @@ parts:
|
|||||||
- libxtst6
|
- libxtst6
|
||||||
source: dist/linux-unpacked
|
source: dist/linux-unpacked
|
||||||
after:
|
after:
|
||||||
- desktop-gtk2
|
- desktop-gtk3
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ envSetup()
|
|||||||
|
|
||||||
# Set name of upstreamRemote
|
# Set name of upstreamRemote
|
||||||
cd $workingDir
|
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 ]
|
if [ $? -eq 0 ]
|
||||||
then
|
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
|
else
|
||||||
upstreamRemote="origin"
|
upstreamRemote="origin"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user