mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-10-23 16:13:37 +00:00
Compare commits
26 Commits
v4.0.0
...
v4.0.2-bet
Author | SHA1 | Date | |
---|---|---|---|
|
95a9568ece | ||
|
e7a885a1fb | ||
|
17d4d97e2e | ||
|
3b14684058 | ||
|
7d592a0a1c | ||
|
eb1be7106b | ||
|
1da6e5d51d | ||
|
dae7089c7e | ||
|
30b40e2ff2 | ||
|
b76f01349a | ||
|
8446deb673 | ||
|
d4b9663257 | ||
|
77044fd9fa | ||
|
177b77f0b5 | ||
|
99b154b8ae | ||
|
3fd8aedf81 | ||
|
b4d2e55c6f | ||
|
3c701ff518 | ||
|
1f79a97b05 | ||
|
90e8e9a806 | ||
|
59ef505efd | ||
|
8d0a111c91 | ||
|
a10fa8f3ad | ||
|
39427091f5 | ||
|
f8d93cf397 | ||
|
ab62b8b5bb |
@@ -6,7 +6,7 @@ The following is a set of guidelines for contributing to Zulip's desktop Client.
|
||||
|
||||
## 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](https://jlord.dev/blog/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.us/essential-electron) great article.
|
||||
|
||||
## Community
|
||||
|
||||
|
@@ -18,6 +18,15 @@ Please see the [installation guide](https://zulipchat.com/help/desktop-app-insta
|
||||
* Multi-language spell checker
|
||||
* Automatic updates
|
||||
|
||||
# Reporting issues
|
||||
|
||||
This desktop client shares most of its code with the Zulip webapp.
|
||||
Issues in an individual organization's Zulip window should be reported
|
||||
in the [Zulip server and webapp
|
||||
project](https://github.com/zulip/zulip/issues/new). Other
|
||||
issues in the desktop app and its settings should be reported [in this
|
||||
project](https://github.com/zulip/zulip-desktop/issues/new).
|
||||
|
||||
# Contribute
|
||||
|
||||
First, join us on the [Zulip community server](https://zulip.readthedocs.io/en/latest/contributing/chat-zulip-org.html)!
|
||||
|
@@ -8,7 +8,7 @@ import path = require('path');
|
||||
import fs = require('fs');
|
||||
import isDev = require('electron-is-dev');
|
||||
import electron = require('electron');
|
||||
const { app, ipcMain } = electron;
|
||||
const { app, ipcMain, session } = electron;
|
||||
|
||||
import AppMenu = require('./menu');
|
||||
import BadgeSettings = require('../renderer/js/pages/preference/badge-settings');
|
||||
@@ -94,6 +94,9 @@ function createMainWindow(): Electron.BrowserWindow {
|
||||
|
||||
// Keep the app running in background on close event
|
||||
win.on('close', e => {
|
||||
if (ConfigUtil.getConfigItem("quitOnClose")) {
|
||||
app.quit();
|
||||
}
|
||||
if (!isQuitting) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -182,6 +185,10 @@ app.on('ready', () => {
|
||||
} else {
|
||||
mainWindow.show();
|
||||
}
|
||||
if (!ConfigUtil.isConfigItemExists('userAgent')) {
|
||||
const userAgent = session.fromPartition('webview:persistsession').getUserAgent();
|
||||
ConfigUtil.setConfigItem('userAgent', userAgent);
|
||||
}
|
||||
});
|
||||
|
||||
page.once('did-frame-finish-load', () => {
|
||||
@@ -362,6 +369,26 @@ app.on('ready', () => {
|
||||
ipcMain.on('save-last-tab', (_event: Electron.IpcMessageEvent, index: number) => {
|
||||
ConfigUtil.setConfigItem('lastActiveTab', index);
|
||||
});
|
||||
|
||||
// Update user idle status for each realm after every 15s
|
||||
const idleCheckInterval = 15 * 1000; // 15 seconds
|
||||
setInterval(() => {
|
||||
// Set user idle if no activity in 1 second (idleThresholdSeconds)
|
||||
const idleThresholdSeconds = 1; // 1 second
|
||||
|
||||
// TODO: Remove typecast to any when types get added
|
||||
// TODO: use powerMonitor.getSystemIdleState when upgrading electron
|
||||
// powerMonitor.querySystemIdleState is deprecated in current electron
|
||||
// version at the time of writing.
|
||||
const powerMonitor = electron.powerMonitor as any;
|
||||
powerMonitor.querySystemIdleState(idleThresholdSeconds, (idleState: string) => {
|
||||
if (idleState === 'active') {
|
||||
page.send('set-active');
|
||||
} else {
|
||||
page.send('set-idle');
|
||||
}
|
||||
});
|
||||
}, idleCheckInterval);
|
||||
});
|
||||
|
||||
app.on('before-quit', () => {
|
||||
|
2
app/package-lock.json
generated
2
app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zulip",
|
||||
"version": "3.1.0-beta",
|
||||
"version": "4.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "zulip",
|
||||
"productName": "Zulip",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.2-beta",
|
||||
"desktopName": "zulip.desktop",
|
||||
"description": "Zulip Desktop App",
|
||||
"license": "Apache-2.0",
|
||||
"copyright": "Kandra Labs, Inc.",
|
||||
@@ -30,6 +31,7 @@
|
||||
"@sentry/electron": "0.14.0",
|
||||
"adm-zip": "0.4.11",
|
||||
"auto-launch": "5.0.5",
|
||||
"backoff": "2.5.0",
|
||||
"dotenv": "8.0.0",
|
||||
"electron-is-dev": "0.3.0",
|
||||
"electron-log": "2.2.14",
|
||||
@@ -38,7 +40,6 @@
|
||||
"electron-window-state": "5.0.3",
|
||||
"escape-html": "1.0.3",
|
||||
"i18n": "0.8.3",
|
||||
"is-online": "7.0.0",
|
||||
"node-json-db": "0.9.2",
|
||||
"request": "2.85.0",
|
||||
"semver": "5.4.1",
|
||||
|
@@ -17,27 +17,43 @@ body {
|
||||
}
|
||||
|
||||
#title {
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#subtitle {
|
||||
font-size: 20px;
|
||||
text-align: left;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
#description {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#reconnect {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#settings {
|
||||
margin-left: 116px;
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 16px;
|
||||
background: rgba(0, 150, 136, 1.000);
|
||||
color: rgba(255, 255, 255, 1.000);
|
||||
width: 84px;
|
||||
width: 96px;
|
||||
height: 32px;
|
||||
border-radius: 5px;
|
||||
line-height: 32px;
|
||||
margin: 20px auto 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#reconnect:hover {
|
||||
.button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
@@ -642,6 +642,26 @@ input.toggle-round:checked + label::after {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.server-network-option {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
margin-top: 10px;
|
||||
padding-top: 15px;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: rgb(78, 191, 172);
|
||||
width: 98%;
|
||||
height: 46px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
i.open-network-button {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
padding-left: 5px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* responsive grid */
|
||||
|
||||
@media (max-width: 650px) {
|
||||
|
@@ -25,6 +25,10 @@ class Tab extends BaseComponent {
|
||||
this.$el.addEventListener('mouseout', this.props.onHoverOut);
|
||||
}
|
||||
|
||||
showNetworkError(): void {
|
||||
this.webview.forceLoad();
|
||||
}
|
||||
|
||||
activate(): void {
|
||||
this.$el.classList.add('active');
|
||||
this.webview.load();
|
||||
|
@@ -125,7 +125,9 @@ class WebView extends BaseComponent {
|
||||
const hasConnectivityErr = SystemUtil.connectivityERR.includes(errorDescription);
|
||||
if (hasConnectivityErr) {
|
||||
console.error('error', errorDescription);
|
||||
this.props.onNetworkError();
|
||||
if (!this.props.url.includes('network.html')) {
|
||||
this.props.onNetworkError(this.props.index);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -152,6 +154,10 @@ class WebView extends BaseComponent {
|
||||
return messageCountInTitle ? Number(messageCountInTitle[1]) : 0;
|
||||
}
|
||||
|
||||
showNotificationSettings(): void {
|
||||
this.$el.executeJavaScript('showNotificationSettings()');
|
||||
}
|
||||
|
||||
show(): void {
|
||||
// Do not show WebView if another tab was selected and this tab should be in background.
|
||||
if (!this.props.isActive()) {
|
||||
@@ -279,6 +285,10 @@ class WebView extends BaseComponent {
|
||||
this.$el.reload();
|
||||
}
|
||||
|
||||
forceLoad(): void {
|
||||
this.init();
|
||||
}
|
||||
|
||||
send(channel: string, ...param: any[]): void {
|
||||
this.$el.send(channel, ...param);
|
||||
}
|
||||
|
@@ -9,7 +9,20 @@ type ListenerType = ((...args: any[]) => void);
|
||||
// for the whole file.
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
class ElectronBridge extends events {
|
||||
send_notification_reply_message_supported = false;
|
||||
send_notification_reply_message_supported: boolean;
|
||||
idle_on_system: boolean;
|
||||
last_active_on_system: number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.send_notification_reply_message_supported = false;
|
||||
// Indicates if the user is idle or not
|
||||
this.idle_on_system = false;
|
||||
|
||||
// Indicates the time at which user was last active
|
||||
this.last_active_on_system = Date.now();
|
||||
}
|
||||
|
||||
send_event(eventName: string | symbol, ...args: any[]): void {
|
||||
this.emit(eventName, ...args);
|
||||
}
|
||||
|
@@ -23,11 +23,6 @@ import CommonUtil = require('./utils/common-util');
|
||||
import EnterpriseUtil = require('./utils/enterprise-util');
|
||||
import Messages = require('./../../resources/messages');
|
||||
|
||||
const logger = new Logger({
|
||||
file: 'errors.log',
|
||||
timestamp: true
|
||||
});
|
||||
|
||||
interface FunctionalTabProps {
|
||||
name: string;
|
||||
materialIcon: string;
|
||||
@@ -63,11 +58,17 @@ interface SettingsOptions {
|
||||
};
|
||||
downloadsPath: string;
|
||||
showDownloadFolder: boolean;
|
||||
quitOnClose: boolean;
|
||||
flashTaskbarOnMessage?: boolean;
|
||||
dockBouncing?: boolean;
|
||||
loading?: AnyObject;
|
||||
}
|
||||
|
||||
const logger = new Logger({
|
||||
file: 'errors.log',
|
||||
timestamp: true
|
||||
});
|
||||
|
||||
const rendererDirectory = path.resolve(__dirname, '..');
|
||||
type ServerOrFunctionalTab = ServerTab | FunctionalTab;
|
||||
|
||||
@@ -206,7 +207,8 @@ class ServerManagerView {
|
||||
silent: false
|
||||
},
|
||||
downloadsPath: `${app.getPath('downloads')}`,
|
||||
showDownloadFolder: false
|
||||
showDownloadFolder: false,
|
||||
quitOnClose: false
|
||||
};
|
||||
|
||||
// Platform specific settings
|
||||
@@ -312,11 +314,24 @@ class ServerManagerView {
|
||||
if (servers.length > 0) {
|
||||
for (let i = 0; i < servers.length; i++) {
|
||||
this.initServer(servers[i], i);
|
||||
DomainUtil.updateSavedServer(servers[i].url, i);
|
||||
this.activateTab(i);
|
||||
}
|
||||
// Open last active tab
|
||||
this.activateTab(ConfigUtil.getConfigItem('lastActiveTab'));
|
||||
let lastActiveTab = ConfigUtil.getConfigItem('lastActiveTab');
|
||||
if (lastActiveTab >= servers.length) {
|
||||
lastActiveTab = 0;
|
||||
}
|
||||
// checkDomain() and webview.load() for lastActiveTab before the others
|
||||
DomainUtil.updateSavedServer(servers[lastActiveTab].url, lastActiveTab);
|
||||
this.activateTab(lastActiveTab);
|
||||
for (let i = 0; i < servers.length; i++) {
|
||||
// after the lastActiveTab is activated, we load the others in the background
|
||||
// without activating them, to prevent flashing of server icons
|
||||
if (i === lastActiveTab) {
|
||||
continue;
|
||||
}
|
||||
DomainUtil.updateSavedServer(servers[i].url, i);
|
||||
this.tabs[i].webview.load();
|
||||
}
|
||||
// Remove focus from the settings icon at sidebar bottom
|
||||
this.$settingsButton.classList.remove('active');
|
||||
} else if (this.presetOrgs.length === 0) {
|
||||
@@ -357,7 +372,7 @@ class ServerManagerView {
|
||||
}
|
||||
this.showLoading(this.loading[this.tabs[this.activeTabIndex].webview.props.url]);
|
||||
},
|
||||
onNetworkError: this.openNetworkTroubleshooting.bind(this),
|
||||
onNetworkError: (index: number) => this.openNetworkTroubleshooting(index),
|
||||
onTitleChange: this.updateBadge.bind(this),
|
||||
nodeIntegration: false,
|
||||
preload: true
|
||||
@@ -523,7 +538,7 @@ class ServerManagerView {
|
||||
}
|
||||
this.showLoading(this.loading[this.tabs[this.activeTabIndex].webview.props.url]);
|
||||
},
|
||||
onNetworkError: this.openNetworkTroubleshooting.bind(this),
|
||||
onNetworkError: (index: number) => this.openNetworkTroubleshooting(index),
|
||||
onTitleChange: this.updateBadge.bind(this),
|
||||
nodeIntegration: true,
|
||||
preload: false
|
||||
@@ -555,12 +570,11 @@ class ServerManagerView {
|
||||
});
|
||||
}
|
||||
|
||||
openNetworkTroubleshooting(): void {
|
||||
this.openFunctionalTab({
|
||||
name: 'Network Troubleshooting',
|
||||
materialIcon: 'network_check',
|
||||
url: `file://${rendererDirectory}/network.html`
|
||||
});
|
||||
openNetworkTroubleshooting(index: number): void {
|
||||
const reconnectUtil = new ReconnectUtil(this.tabs[index].webview);
|
||||
reconnectUtil.pollInternetAndReload();
|
||||
this.tabs[index].webview.props.url = `file://${rendererDirectory}/network.html`;
|
||||
this.tabs[index].showNetworkError();
|
||||
}
|
||||
|
||||
activateLastTab(index: number): void {
|
||||
@@ -719,6 +733,11 @@ class ServerManagerView {
|
||||
this.$dndButton.querySelector('i').textContent = alert ? 'notifications_off' : 'notifications';
|
||||
}
|
||||
|
||||
isLoggedIn(tabIndex: number): boolean {
|
||||
const url = this.tabs[tabIndex].webview.$el.src;
|
||||
return !(url.endsWith('/login/') || this.tabs[tabIndex].webview.loading);
|
||||
}
|
||||
|
||||
addContextMenu($serverImg: HTMLImageElement, index: number): void {
|
||||
$serverImg.addEventListener('contextmenu', e => {
|
||||
e.preventDefault();
|
||||
@@ -743,6 +762,15 @@ class ServerManagerView {
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Notification settings',
|
||||
enabled: this.isLoggedIn(index),
|
||||
click: () => {
|
||||
// switch to tab whose icon was right-clicked
|
||||
this.activateTab(index);
|
||||
this.tabs[index].webview.showNotificationSettings();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Copy Zulip URL',
|
||||
click: () => {
|
||||
@@ -778,6 +806,10 @@ class ServerManagerView {
|
||||
});
|
||||
}
|
||||
|
||||
ipcRenderer.on('show-network-error', (event: Event, index: number) => {
|
||||
this.openNetworkTroubleshooting(index);
|
||||
});
|
||||
|
||||
ipcRenderer.on('open-settings', (event: Event, settingNav: string) => {
|
||||
this.openSettings(settingNav);
|
||||
});
|
||||
@@ -961,22 +993,30 @@ class ServerManagerView {
|
||||
ipcRenderer.on('new-server', () => {
|
||||
this.openSettings('AddServer');
|
||||
});
|
||||
|
||||
ipcRenderer.on('set-active', () => {
|
||||
const webviews: NodeListOf<Electron.WebviewTag> = document.querySelectorAll('webview');
|
||||
webviews.forEach(webview => {
|
||||
webview.send('set-active');
|
||||
});
|
||||
});
|
||||
|
||||
ipcRenderer.on('set-idle', () => {
|
||||
const webviews: NodeListOf<Electron.WebviewTag> = document.querySelectorAll('webview');
|
||||
webviews.forEach(webview => {
|
||||
webview.send('set-idle');
|
||||
});
|
||||
});
|
||||
|
||||
ipcRenderer.on('open-network-settings', () => {
|
||||
this.openSettings('Network');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const serverManagerView = new ServerManagerView();
|
||||
const reconnectUtil = new ReconnectUtil(serverManagerView);
|
||||
serverManagerView.init();
|
||||
window.addEventListener('online', () => {
|
||||
reconnectUtil.pollInternetAndReload();
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
reconnectUtil.clearState();
|
||||
logger.log('No internet connection, you are offline.');
|
||||
});
|
||||
|
||||
// only start electron-connect (auto reload on change) when its ran
|
||||
// from `npm run dev` or `gulp dev` and not from `npm start` when
|
||||
// app is started `npm start` main process's proces.argv will have
|
||||
|
@@ -3,19 +3,14 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
class NetworkTroubleshootingView {
|
||||
$reconnectButton: Element;
|
||||
constructor() {
|
||||
this.$reconnectButton = document.querySelector('#reconnect');
|
||||
}
|
||||
|
||||
init(): void {
|
||||
this.$reconnectButton.addEventListener('click', () => {
|
||||
init($reconnectButton: Element, $settingsButton: Element): void {
|
||||
$reconnectButton.addEventListener('click', () => {
|
||||
ipcRenderer.send('forward-message', 'reload-viewer');
|
||||
});
|
||||
$settingsButton.addEventListener('click', () => {
|
||||
ipcRenderer.send('forward-message', 'open-settings');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const networkTroubleshootingView = new NetworkTroubleshootingView();
|
||||
networkTroubleshootingView.init();
|
||||
});
|
||||
export = new NetworkTroubleshootingView();
|
||||
|
@@ -18,11 +18,11 @@ class BadgeSettings {
|
||||
}
|
||||
|
||||
showBadgeCount(messageCount: number, mainWindow: electron.BrowserWindow): void {
|
||||
if (process.platform === 'darwin') {
|
||||
app.setBadgeCount(messageCount);
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
this.updateOverlayIcon(messageCount, mainWindow);
|
||||
} else {
|
||||
// This should work on both macOS and Linux
|
||||
app.setBadgeCount(messageCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -42,7 +42,7 @@ class GeneralSection extends BaseSection {
|
||||
<div class="setting-control"></div>
|
||||
</div>
|
||||
<div class="setting-row" id="dock-bounce-option" style= "display:${process.platform === 'darwin' ? '' : 'none'}">
|
||||
<div class="setting-description">${t.__('Bounce dock on new private message')})}</div>
|
||||
<div class="setting-description">${t.__('Bounce dock on new private message')}</div>
|
||||
<div class="setting-control"></div>
|
||||
</div>
|
||||
<div class="setting-row" id="flash-taskbar-option" style= "display:${process.platform === 'win32' ? '' : 'none'}">
|
||||
@@ -82,6 +82,10 @@ class GeneralSection extends BaseSection {
|
||||
<div class="setting-description">${t.__('Always start minimized')}</div>
|
||||
<div class="setting-control"></div>
|
||||
</div>
|
||||
<div class="setting-row" id="quitOnClose-option">
|
||||
<div class="setting-description">${t.__('Quit when the window is closed')}</div>
|
||||
<div class="setting-control"></div>
|
||||
</div>
|
||||
<div class="setting-row" id="enable-spellchecker-option">
|
||||
<div class="setting-description">${t.__('Enable spellchecker (requires restart)')}</div>
|
||||
<div class="setting-control"></div>
|
||||
@@ -155,6 +159,7 @@ class GeneralSection extends BaseSection {
|
||||
this.removeCustomCSS();
|
||||
this.downloadFolder();
|
||||
this.showDownloadFolder();
|
||||
this.updateQuitOnCloseOption();
|
||||
this.enableErrorReporting();
|
||||
|
||||
// Platform specific settings
|
||||
@@ -321,6 +326,18 @@ class GeneralSection extends BaseSection {
|
||||
});
|
||||
}
|
||||
|
||||
updateQuitOnCloseOption(): void {
|
||||
this.generateSettingOption({
|
||||
$element: document.querySelector('#quitOnClose-option .setting-control'),
|
||||
value: ConfigUtil.getConfigItem('quitOnClose', false),
|
||||
clickHandler: () => {
|
||||
const newValue = !ConfigUtil.getConfigItem('quitOnClose');
|
||||
ConfigUtil.setConfigItem('quitOnClose', newValue);
|
||||
this.updateQuitOnCloseOption();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enableSpellchecker(): void {
|
||||
this.generateSettingOption({
|
||||
$element: document.querySelector('#enable-spellchecker-option .setting-control'),
|
||||
|
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
import { shell } from 'electron';
|
||||
import { shell, ipcRenderer } from 'electron';
|
||||
|
||||
import BaseComponent = require('../../components/base');
|
||||
import DomainUtil = require('../../utils/domain-util');
|
||||
@@ -30,15 +30,21 @@ class NewServerForm extends BaseComponent {
|
||||
</div>
|
||||
</div>
|
||||
<div class="server-center">
|
||||
<div class="divider">
|
||||
<hr class="left"/>${t.__('OR')}<hr class="right" />
|
||||
</div>
|
||||
<div class="divider">
|
||||
<hr class="left"/>${t.__('OR')}<hr class="right" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="server-center">
|
||||
<div class="server-save-action">
|
||||
<button id="open-create-org-link">${t.__('Create a new organization')}</button>
|
||||
</div>
|
||||
<div class="server-save-action">
|
||||
<button id="open-create-org-link">${t.__('Create a new organization')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="server-center">
|
||||
<div class="server-network-option">
|
||||
<span id="open-network-settings">${t.__('Network and Proxy Settings')}</span>
|
||||
<i class="material-icons open-network-button">open_in_new</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -76,6 +82,11 @@ class NewServerForm extends BaseComponent {
|
||||
});
|
||||
}
|
||||
|
||||
networkSettingsLink(): void {
|
||||
const networkSettingsId = document.querySelectorAll('.server-network-option')[0];
|
||||
networkSettingsId.addEventListener('click', () => ipcRenderer.send('forward-message', 'open-network-settings'));
|
||||
}
|
||||
|
||||
initActions(): void {
|
||||
this.$saveServerButton.addEventListener('click', () => {
|
||||
this.submitFormHandler();
|
||||
@@ -89,6 +100,7 @@ class NewServerForm extends BaseComponent {
|
||||
});
|
||||
// open create new org link in default browser
|
||||
this.openCreateNewOrgExternalLink();
|
||||
this.networkSettingsLink();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,23 @@
|
||||
// we have and will have some non camelcase stuff
|
||||
// while working with zulip and electron bridge
|
||||
// so turning the rule off for the whole file.
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
'use strict';
|
||||
|
||||
import { ipcRenderer, shell } from 'electron';
|
||||
import SetupSpellChecker from './spellchecker';
|
||||
|
||||
import isDev = require('electron-is-dev');
|
||||
import LinkUtil = require('./utils/link-util');
|
||||
import params = require('./utils/params-util');
|
||||
|
||||
import NetworkError = require('./pages/network');
|
||||
|
||||
interface PatchedGlobal extends NodeJS.Global {
|
||||
logout: () => void;
|
||||
shortcut: () => void;
|
||||
showNotificationSettings: () => void;
|
||||
}
|
||||
|
||||
const globalPatched = global as PatchedGlobal;
|
||||
@@ -21,7 +30,6 @@ require(__dirname + '/shared/preventdrag.js');
|
||||
|
||||
declare let window: ZulipWebWindow;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
window.electron_bridge = require('./electron-bridge');
|
||||
|
||||
const logout = (): void => {
|
||||
@@ -46,16 +54,33 @@ const shortcut = (): void => {
|
||||
}
|
||||
};
|
||||
|
||||
const showNotificationSettings = (): void => {
|
||||
// Create the menu for the below
|
||||
const dropdown: HTMLElement = document.querySelector('.dropdown-toggle');
|
||||
dropdown.click();
|
||||
|
||||
const nodes: NodeListOf<HTMLElement> = document.querySelectorAll('.dropdown-menu li a');
|
||||
nodes[2].click();
|
||||
|
||||
const notificationItem: NodeListOf<HTMLElement> = document.querySelectorAll('.normal-settings-list li div');
|
||||
|
||||
// wait until the notification dom element shows up
|
||||
setTimeout(() => {
|
||||
notificationItem[2].click();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
process.once('loaded', (): void => {
|
||||
globalPatched.logout = logout;
|
||||
globalPatched.shortcut = shortcut;
|
||||
globalPatched.showNotificationSettings = showNotificationSettings;
|
||||
});
|
||||
|
||||
// To prevent failing this script on linux we need to load it after the document loaded
|
||||
document.addEventListener('DOMContentLoaded', (): void => {
|
||||
if (params.isPageParams()) {
|
||||
// Get the default language of the server
|
||||
const serverLanguage = page_params.default_language; // eslint-disable-line no-undef, @typescript-eslint/camelcase
|
||||
const serverLanguage = page_params.default_language; // eslint-disable-line no-undef
|
||||
if (serverLanguage) {
|
||||
// Init spellchecker
|
||||
SetupSpellChecker.init(serverLanguage);
|
||||
@@ -97,6 +122,15 @@ window.addEventListener('beforeunload', (): void => {
|
||||
SetupSpellChecker.unsubscribeSpellChecker();
|
||||
});
|
||||
|
||||
window.addEventListener('load', (event: any): void => {
|
||||
if (!event.target.URL.includes('app/renderer/network.html')) {
|
||||
return;
|
||||
}
|
||||
const $reconnectButton = document.querySelector('#reconnect');
|
||||
const $settingsButton = document.querySelector('#settings');
|
||||
NetworkError.init($reconnectButton, $settingsButton);
|
||||
});
|
||||
|
||||
// electron's globalShortcut can cause unexpected results
|
||||
// so adding the reload shortcut in the old-school way
|
||||
// Zoom from numpad keys is not supported by electron, so adding it through listeners.
|
||||
@@ -112,3 +146,20 @@ document.addEventListener('keydown', event => {
|
||||
ipcRenderer.send('forward-message', 'zoomActualSize');
|
||||
}
|
||||
});
|
||||
|
||||
// Set user as active and update the time of last activity
|
||||
ipcRenderer.on('set-active', () => {
|
||||
if (isDev) {
|
||||
console.log('active');
|
||||
}
|
||||
window.electron_bridge.idle_on_system = false;
|
||||
window.electron_bridge.last_active_on_system = Date.now();
|
||||
});
|
||||
|
||||
// Set user as idle and time of last activity is left unchanged
|
||||
ipcRenderer.on('set-idle', () => {
|
||||
if (isDev) {
|
||||
console.log('idle');
|
||||
}
|
||||
window.electron_bridge.idle_on_system = true;
|
||||
});
|
||||
|
@@ -63,7 +63,7 @@ class CertificateUtil {
|
||||
}
|
||||
|
||||
setCertificate(server: string, fileName: string): void {
|
||||
const filePath = `${certificatesDir}/${fileName}`;
|
||||
const filePath = `${fileName}`;
|
||||
this.db.push(`/${server}`, filePath, true);
|
||||
this.reloadDB();
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import RequestUtil = require('./request-util');
|
||||
import EnterpriseUtil = require('./enterprise-util');
|
||||
import Messages = require('../../../resources/messages');
|
||||
|
||||
const { ipcRenderer } = electron;
|
||||
const { app, dialog } = electron.remote;
|
||||
|
||||
const logger = new Logger({
|
||||
@@ -59,6 +60,16 @@ class DomainUtil {
|
||||
return this.db.getData(`/domains[${index}]`);
|
||||
}
|
||||
|
||||
shouldIgnoreCerts(url: string): boolean {
|
||||
const domains = this.getDomains();
|
||||
for (const domain of domains) {
|
||||
if (domain.url === url) {
|
||||
return domain.ignoreCerts;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
updateDomain(index: number, server: object): void {
|
||||
this.reloadDB();
|
||||
this.db.push(`/domains[${index}]`, server, true);
|
||||
@@ -250,19 +261,21 @@ class DomainUtil {
|
||||
});
|
||||
}
|
||||
|
||||
updateSavedServer(url: string, index: number): void {
|
||||
async updateSavedServer(url: string, index: number): Promise<void> {
|
||||
// Does not promise successful update
|
||||
const oldIcon = this.getDomain(index).icon;
|
||||
const { ignoreCerts } = this.getDomain(index);
|
||||
this.checkDomain(url, ignoreCerts, true).then(newServerConf => {
|
||||
this.saveServerIcon(newServerConf, ignoreCerts).then(localIconUrl => {
|
||||
if (!oldIcon || localIconUrl !== '../renderer/img/icon.png') {
|
||||
newServerConf.icon = localIconUrl;
|
||||
this.updateDomain(index, newServerConf);
|
||||
this.reloadDB();
|
||||
}
|
||||
});
|
||||
});
|
||||
try {
|
||||
const newServerConf = await this.checkDomain(url, ignoreCerts, true);
|
||||
const localIconUrl = await this.saveServerIcon(newServerConf, ignoreCerts);
|
||||
if (!oldIcon || localIconUrl !== '../renderer/img/icon.png') {
|
||||
newServerConf.icon = localIconUrl;
|
||||
this.updateDomain(index, newServerConf);
|
||||
this.reloadDB();
|
||||
}
|
||||
} catch (err) {
|
||||
ipcRenderer.send('forward-message', 'show-network-error', index);
|
||||
}
|
||||
}
|
||||
|
||||
reloadDB(): void {
|
||||
|
@@ -1,5 +1,10 @@
|
||||
import isOnline = require('is-online');
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import backoff = require('backoff');
|
||||
import request = require('request');
|
||||
import Logger = require('./logger-util');
|
||||
import RequestUtil = require('./request-util');
|
||||
import DomainUtil = require('./domain-util');
|
||||
|
||||
const logger = new Logger({
|
||||
file: `domain-util.log`,
|
||||
@@ -7,43 +12,73 @@ const logger = new Logger({
|
||||
});
|
||||
|
||||
class ReconnectUtil {
|
||||
// TODO: TypeScript - Figure out how to annotate serverManagerView
|
||||
// it should be ServerManagerView; maybe make it a generic so we can
|
||||
// pass the class from main.js
|
||||
serverManagerView: any;
|
||||
// TODO: TypeScript - Figure out how to annotate webview
|
||||
// it should be WebView; maybe make it a generic so we can
|
||||
// pass the class from main.ts
|
||||
webview: any;
|
||||
url: string;
|
||||
alreadyReloaded: boolean;
|
||||
fibonacciBackoff: any;
|
||||
|
||||
constructor(serverManagerView: any) {
|
||||
this.serverManagerView = serverManagerView;
|
||||
constructor(webview: any) {
|
||||
this.webview = webview;
|
||||
this.url = webview.props.url;
|
||||
this.alreadyReloaded = false;
|
||||
this.clearState();
|
||||
}
|
||||
|
||||
clearState(): void {
|
||||
this.alreadyReloaded = false;
|
||||
this.fibonacciBackoff = backoff.fibonacci({
|
||||
initialDelay: 5000,
|
||||
maxDelay: 300000
|
||||
});
|
||||
}
|
||||
|
||||
isOnline(): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
try {
|
||||
const ignoreCerts = DomainUtil.shouldIgnoreCerts(this.url);
|
||||
if (ignoreCerts === null) {
|
||||
return;
|
||||
}
|
||||
request(
|
||||
{
|
||||
url: `${this.url}/static/favicon.ico`,
|
||||
...RequestUtil.requestOptions(this.url, ignoreCerts)
|
||||
},
|
||||
(error: Error, response: any) => {
|
||||
const isValidResponse =
|
||||
!error && response.statusCode >= 200 && response.statusCode < 400;
|
||||
resolve(isValidResponse);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
logger.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pollInternetAndReload(): void {
|
||||
const pollInterval = setInterval(() => {
|
||||
this._checkAndReload()
|
||||
.then(status => {
|
||||
if (status) {
|
||||
this.alreadyReloaded = true;
|
||||
clearInterval(pollInterval);
|
||||
}
|
||||
});
|
||||
}, 1500);
|
||||
this.fibonacciBackoff.backoff();
|
||||
this.fibonacciBackoff.on('ready', () => {
|
||||
this._checkAndReload().then(status => {
|
||||
if (status) {
|
||||
this.fibonacciBackoff.reset();
|
||||
} else {
|
||||
this.fibonacciBackoff.backoff();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Make this a async function
|
||||
_checkAndReload(): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
if (!this.alreadyReloaded) { // eslint-disable-line no-negated-condition
|
||||
isOnline()
|
||||
this.isOnline()
|
||||
.then((online: boolean) => {
|
||||
if (online) {
|
||||
if (!this.alreadyReloaded) {
|
||||
this.serverManagerView.reloadCurrentView();
|
||||
}
|
||||
ipcRenderer.send('forward-message', 'reload-viewer');
|
||||
logger.log('You\'re back online.');
|
||||
return resolve(true);
|
||||
}
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import { remote } from 'electron';
|
||||
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import ConfigUtil = require('./config-util');
|
||||
import Logger = require('./logger-util');
|
||||
import ProxyUtil = require('./proxy-util');
|
||||
import CertificateUtil = require('./certificate-util');
|
||||
import SystemUtil = require('./system-util');
|
||||
|
||||
const { app } = remote;
|
||||
|
||||
const logger = new Logger({
|
||||
file: `request-util.log`,
|
||||
timestamp: true
|
||||
@@ -38,11 +43,20 @@ class RequestUtil {
|
||||
const certificate = CertificateUtil.getCertificate(
|
||||
encodeURIComponent(domain)
|
||||
);
|
||||
|
||||
let certificateFile = null;
|
||||
if (certificate && certificate.includes('/')) {
|
||||
// certificate saved using old app version
|
||||
certificateFile = certificate;
|
||||
} else if (certificate) {
|
||||
certificateFile = path.join(`${app.getPath('userData')}/certificates`, certificate);
|
||||
}
|
||||
|
||||
let certificateLocation = '';
|
||||
if (certificate) {
|
||||
// To handle case where certificate has been moved from the location in certificates.json
|
||||
try {
|
||||
certificateLocation = fs.readFileSync(certificate, 'utf8');
|
||||
certificateLocation = fs.readFileSync(certificateFile, 'utf8');
|
||||
} catch (err) {
|
||||
logger.warn(`Error while trying to get certificate: ${err}`);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import { remote } from 'electron';
|
||||
|
||||
import os = require('os');
|
||||
import ConfigUtil = require('./config-util');
|
||||
|
||||
const { app } = remote;
|
||||
let instance: null | SystemUtil = null;
|
||||
@@ -53,6 +54,9 @@ class SystemUtil {
|
||||
}
|
||||
|
||||
getUserAgent(): string | null {
|
||||
if (!this.userAgent) {
|
||||
this.setUserAgent(ConfigUtil.getConfigItem('userAgent', null));
|
||||
}
|
||||
return this.userAgent;
|
||||
}
|
||||
}
|
||||
|
@@ -1,29 +0,0 @@
|
||||
'use strict';
|
||||
const path = require("path");
|
||||
const electron = require("electron");
|
||||
const i18n = require("i18n");
|
||||
let instance = null;
|
||||
let app = null;
|
||||
/* To make the util runnable in both main and renderer process */
|
||||
if (process.type === 'renderer') {
|
||||
app = electron.remote.app;
|
||||
}
|
||||
else {
|
||||
app = electron.app;
|
||||
}
|
||||
class TranslationUtil {
|
||||
constructor() {
|
||||
if (instance) {
|
||||
return this;
|
||||
}
|
||||
instance = this;
|
||||
i18n.configure({
|
||||
directory: path.join(__dirname, '../../../translations/'),
|
||||
register: this
|
||||
});
|
||||
}
|
||||
__(phrase) {
|
||||
return i18n.__({ phrase, locale: app.getLocale() });
|
||||
}
|
||||
}
|
||||
module.exports = new TranslationUtil();
|
@@ -9,14 +9,21 @@
|
||||
<body>
|
||||
<div id="content">
|
||||
<div id="picture"><img src="img/zulip_network.png"></div>
|
||||
<div id="title">Zulip can't connect</div>
|
||||
<div id="description">
|
||||
<div>Your computer seems to be offline.</div>
|
||||
<div>We will keep trying to reconnect, or you can try now.</div>
|
||||
<div id="title">We can't connect to this organization</div>
|
||||
<div id="subtitle">This could be because</div>
|
||||
<ul id="description">
|
||||
<li>You're not online or your proxy is misconfigured.</li>
|
||||
<li>There is no Zulip organization hosted at this URL.</li>
|
||||
<li>This Zulip organization is temporarily unavailable.</li>
|
||||
<li>This Zulip organization has been moved or deleted.</li>
|
||||
</ul>
|
||||
<div id="buttons">
|
||||
<div id="reconnect" class="button">Reconnect</div>
|
||||
<div id="settings" class="button">Settings</div>
|
||||
</div>
|
||||
<div id="reconnect">Try now</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="js/pages/network.js"></script>
|
||||
<script>var exports = {};</script>
|
||||
<script src="js/preload.js"></script>
|
||||
<script>require('./js/shared/preventdrag.js')</script>
|
||||
</html>
|
||||
|
@@ -9,7 +9,9 @@ class Messages {
|
||||
\n • You can connect to that URL in a web browser.\
|
||||
\n • If you need a proxy to connect to the Internet, that you've configured your proxy in the Network settings.\
|
||||
\n • It's a Zulip server. (The oldest supported version is 1.6).\
|
||||
\n • The server has a valid certificate. (You can add custom certificates in Settings > Organizations).`;
|
||||
\n • The server has a valid certificate. (You can add custom certificates in Settings > Organizations). \
|
||||
\n • The SSL is correctly configured for the certificate. Check out the SSL troubleshooting guide -
|
||||
\n https://zulip.readthedocs.io/en/stable/production/ssl-certificates.html`;
|
||||
}
|
||||
|
||||
noOrgsError(domain: string): string {
|
||||
|
20
app/translations/README.md
Normal file
20
app/translations/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# How to help translate Zulip Desktop
|
||||
|
||||
These are *generated* files (*) that contain translations of the strings in
|
||||
the app.
|
||||
|
||||
You can help translate Zulip Desktop into your language! We do our
|
||||
translations in Transifex, which is a nice web app for collaborating on
|
||||
translations; a maintainer then syncs those translations into this repo.
|
||||
To help out, [join the Zulip project on
|
||||
Transifex](https://www.transifex.com/zulip/zulip/) and enter translations
|
||||
there. More details in the [Zulip contributor docs](https://zulip.readthedocs.io/en/latest/translating/translating.html#translators-workflow).
|
||||
|
||||
Within that Transifex project, if you'd like to focus on Zulip Desktop, look
|
||||
at `desktop.json`. The other resources there are for the Zulip web/mobile
|
||||
app, where translations are also very welcome.
|
||||
|
||||
(*) One file is an exception: `en.json` is manually maintained as a
|
||||
list of (English) messages in the source code, and is used when we upload to
|
||||
Transifex a list of strings to be translated. It doesn't contain any
|
||||
translations.
|
118
app/translations/en-GB.json
Normal file
118
app/translations/en-GB.json
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"Add Organization": "Add Organization",
|
||||
"Toggle Do Not Disturb": "Toggle Do Not Disturb",
|
||||
"Desktop Settings": "Desktop Settings",
|
||||
"Keyboard Shortcuts": "Keyboard Shortcuts",
|
||||
"Copy Zulip URL": "Copy Zulip URL",
|
||||
"Log Out of Organization": "Log Out of Organization",
|
||||
"Services": "Services",
|
||||
"Hide": "Hide",
|
||||
"Hide Others": "Hide Others",
|
||||
"Unhide": "Unhide",
|
||||
"Minimize": "Minimize",
|
||||
"Close": "Close",
|
||||
"Quit": "Quit",
|
||||
"Edit": "Edit",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Cut": "Cut",
|
||||
"Copy": "Copy",
|
||||
"Paste": "Paste",
|
||||
"Paste and Match Style": "Paste and Match Style",
|
||||
"Select All": "Select All",
|
||||
"View": "View",
|
||||
"Reload": "Reload",
|
||||
"Hard Reload": "Hard Reload",
|
||||
"Toggle Full Screen": "Toggle Full Screen",
|
||||
"Zoom In": "Zoom In",
|
||||
"Zoom Out": "Zoom Out",
|
||||
"Actual Size": "Actual Size",
|
||||
"Toggle Tray Icon": "Toggle Tray Icon",
|
||||
"Toggle Sidebar": "Toggle Sidebar",
|
||||
"Auto hide Menu bar": "Auto hide Menu bar",
|
||||
"History": "History",
|
||||
"Back": "Back",
|
||||
"Forward": "Forward",
|
||||
"Window": "Window",
|
||||
"Tools": "Tools",
|
||||
"Check for Updates": "Check for Updates",
|
||||
"Release Notes": "Release Notes",
|
||||
"Factory Reset": "Factory Reset",
|
||||
"Download App Logs": "Download App Logs",
|
||||
"Toggle DevTools for Zulip App": "Toggle DevTools for Zulip App",
|
||||
"Toggle DevTools for Active Tab": "Toggle DevTools for Active Tab",
|
||||
"Help": "Help",
|
||||
"About Zulip": "About Zulip",
|
||||
"Help Center": "Help Center",
|
||||
"Report an Issue": "Report an Issue",
|
||||
"Switch to Next Organization": "Switch to Next Organization",
|
||||
"Switch to Previous Organization": "Switch to Previous Organization",
|
||||
"General": "General",
|
||||
"Network": "Network",
|
||||
"AddServer": "AddServer",
|
||||
"Organizations": "Organizations",
|
||||
"Shortcuts": "Shortcuts",
|
||||
"Settings": "Settings",
|
||||
"Add a Zulip organization": "Add a Zulip organization",
|
||||
"Organization URL": "Organization URL",
|
||||
"Connect": "Connect",
|
||||
"OR": "OR",
|
||||
"Create a new organization": "Create a new organization",
|
||||
"Proxy": "Proxy",
|
||||
"Use system proxy settings (requires restart)": "Use system proxy settings (requires restart)",
|
||||
"Manual proxy configuration": "Manual proxy configuration",
|
||||
"script": "script",
|
||||
"Proxy rules": "Proxy rules",
|
||||
"Proxy bypass rules": "Proxy bypass rules",
|
||||
"Save": "Save",
|
||||
"Appearance": "Appearance",
|
||||
"Show app icon in system tray": "Show app icon in system tray",
|
||||
"Auto hide menu bar (Press Alt key to display)": "Auto hide menu bar (Press Alt key to display)",
|
||||
"Show sidebar": "Show sidebar",
|
||||
"Show app unread badge": "Show app unread badge",
|
||||
"Bounce dock on new private message": "Bounce dock on new private message",
|
||||
"Flash taskbar on new message": "Flash taskbar on new message",
|
||||
"Desktop Notifications": "Desktop Notifications",
|
||||
"Show desktop notifications": "Show desktop notifications",
|
||||
"Mute all sounds from Zulip": "Mute all sounds from Zulip",
|
||||
"App Updates": "App Updates",
|
||||
"Enable auto updates": "Enable auto updates",
|
||||
"Get beta updates": "Get beta updates",
|
||||
"Functionality": "Functionality",
|
||||
"Start app at login": "Start app at login",
|
||||
"Always start minimized": "Always start minimized",
|
||||
"Enable spellchecker (requires restart)": "Enable spellchecker (requires restart)",
|
||||
"Advanced": "Advanced",
|
||||
"Enable error reporting (requires restart)": "Enable error reporting (requires restart)",
|
||||
"Show downloaded files in file manager": "Show downloaded files in file manager",
|
||||
"Add custom CSS": "Add custom CSS",
|
||||
"Upload": "Upload",
|
||||
"Delete": "Delete",
|
||||
"Default download location": "Default download location",
|
||||
"Change": "Change",
|
||||
"Reset Application Data": "Reset Application Data",
|
||||
"This will delete all application data including all added accounts and preferences": "This will delete all application data including all added accounts and preferences",
|
||||
"Reset App Data": "Reset App Data",
|
||||
"Connected organizations": "Connected organizations",
|
||||
"All the connected orgnizations will appear here.": "All the connected orgnizations will appear here.",
|
||||
"Connect to another organization": "Connect to another organization",
|
||||
"Add Custom Certificates": "Add Custom Certificates",
|
||||
"Find accounts by email": "Find accounts by email",
|
||||
"All the connected orgnizations will appear here": "All the connected orgnizations will appear here",
|
||||
"Disconnect": "Disconnect",
|
||||
"Certificate file": "Certificate file",
|
||||
"Find accounts": "Find accounts",
|
||||
"Tip": "Tip",
|
||||
"These desktop app shortcuts extend the Zulip webapp's": "These desktop app shortcuts extend the Zulip webapp's",
|
||||
"keyboard shortcuts": "keyboard shortcuts",
|
||||
"Application Shortcuts": "Application Shortcuts",
|
||||
"Reset App Settings": "Reset App Settings",
|
||||
"Log Out": "Log Out",
|
||||
"Hide Zulip": "Hide Zulip",
|
||||
"Quit Zulip": "Quit Zulip",
|
||||
"Edit Shortcuts": "Edit Shortcuts",
|
||||
"Emoji & Symbols": "Emoji & Symbols",
|
||||
"View Shortcuts": "View Shortcuts",
|
||||
"Enter Full Screen": "Enter Full Screen",
|
||||
"History Shortcuts": "History Shortcuts"
|
||||
}
|
@@ -105,4 +105,4 @@
|
||||
"View Shortcuts": "View Shortcuts",
|
||||
"History Shortcuts": "History Shortcuts",
|
||||
"Window Shortcuts": "Window Shortcuts"
|
||||
}
|
||||
}
|
||||
|
@@ -113,5 +113,6 @@
|
||||
"Zoom Out": "Zoom Out",
|
||||
"Zulip Help": "Zulip Help",
|
||||
"keyboard shortcuts": "keyboard shortcuts",
|
||||
"script": "script"
|
||||
"script": "script",
|
||||
"Quit when the window is closed": "Quit when the window is closed"
|
||||
}
|
||||
|
@@ -1,58 +1,58 @@
|
||||
{
|
||||
"About Zulip": "О Зулип",
|
||||
"About Zulip": "О Zulip",
|
||||
"Actual Size": "Фактический размер",
|
||||
"Add Custom Certificates": "Добавить пользовательские сертификаты",
|
||||
"Add Organization": "Добавить организацию",
|
||||
"Add a Zulip organization": "Добавить организацию Zulip",
|
||||
"Add custom CSS": "Добавить собственный CSS",
|
||||
"Advanced": "продвинутый",
|
||||
"Advanced": "Расширенные",
|
||||
"All the connected organizations will appear here": "Все связанные организации появятся здесь",
|
||||
"Always start minimized": "Всегда начинайте сворачивать",
|
||||
"App Updates": "Обновления приложений",
|
||||
"Appearance": "Внешность",
|
||||
"Application Shortcuts": "Ярлыки приложений",
|
||||
"Always start minimized": "Всегда запускаться свернутым",
|
||||
"App Updates": "Обновления приложения",
|
||||
"Appearance": "Внешний вид",
|
||||
"Application Shortcuts": "Горячие клавиши приложения",
|
||||
"Are you sure you want to disconnect this organization?": "Вы уверены, что хотите отключить эту организацию?",
|
||||
"Auto hide Menu bar": "Авто скрыть панель меню",
|
||||
"Auto hide menu bar (Press Alt key to display)": "Автоматическое скрытие строки меню (нажмите клавишу Alt для отображения)",
|
||||
"Back": "назад",
|
||||
"Bounce dock on new private message": "Отскок док на новое личное сообщение",
|
||||
"Back": "Назад",
|
||||
"Bounce dock on new private message": "Прыгающий док на новое личное сообщение",
|
||||
"Certificate file": "Файл сертификата",
|
||||
"Change": "+ Изменить",
|
||||
"Check for Updates": "Проверить наличие обновлений",
|
||||
"Close": "близко",
|
||||
"Connect": "соединять",
|
||||
"Close": "Закрыть",
|
||||
"Connect": "Подключиться",
|
||||
"Connect to another organization": "Подключиться к другой организации",
|
||||
"Connected organizations": "Связанные организации",
|
||||
"Copy": "копия",
|
||||
"Copy": "Копировать",
|
||||
"Copy Zulip URL": "Скопируйте Zulip URL",
|
||||
"Create a new organization": "Создать новую организацию",
|
||||
"Cut": "Резать",
|
||||
"Default download location": "Местоположение загрузки по умолчанию",
|
||||
"Delete": "удалять",
|
||||
"Desktop App Settings": "Настройки настольного приложения",
|
||||
"Desktop Notifications": "Уведомления на рабочем столе",
|
||||
"Desktop Settings": "Настройки рабочего стола",
|
||||
"Cut": "Вырезать",
|
||||
"Default download location": "Местоположение загрузок по умолчанию",
|
||||
"Delete": "Удалить",
|
||||
"Desktop App Settings": "Настройки приложения",
|
||||
"Desktop Notifications": "Уведомления в приложении",
|
||||
"Desktop Settings": "Настройки приложения",
|
||||
"Disconnect": "Отключить",
|
||||
"Download App Logs": "Скачать журналы приложений",
|
||||
"Edit": "редактировать",
|
||||
"Edit Shortcuts": "Изменить ярлыки",
|
||||
"Download App Logs": "Скачать журналы приложения",
|
||||
"Edit": "Правка",
|
||||
"Edit Shortcuts": "Изменить горячие клавиши",
|
||||
"Enable auto updates": "Включить автообновления",
|
||||
"Enable error reporting (requires restart)": "Включить отчет об ошибках (требуется перезагрузка)",
|
||||
"Enable spellchecker (requires restart)": "Включить проверку орфографии (требуется перезагрузка)",
|
||||
"Factory Reset": "Сброс к заводским настройкам",
|
||||
"File": "файл",
|
||||
"File": "Файл",
|
||||
"Find accounts": "Найти аккаунты",
|
||||
"Find accounts by email": "Найти аккаунты по электронной почте",
|
||||
"Flash taskbar on new message": "Flash-панель задач на новое сообщение",
|
||||
"Forward": "Вперед",
|
||||
"Functionality": "функциональность",
|
||||
"General": "генеральный",
|
||||
"Functionality": "Функциональность",
|
||||
"General": "Общий",
|
||||
"Get beta updates": "Получить бета-обновления",
|
||||
"Hard Reload": "Жесткая перезагрузка",
|
||||
"Help": "Помогите",
|
||||
"Hard Reload": "Принудительная перезагрузка",
|
||||
"Help": "Помощь",
|
||||
"Help Center": "Центр помощи",
|
||||
"History": "история",
|
||||
"History Shortcuts": "Ярлыки истории",
|
||||
"History": "История",
|
||||
"History Shortcuts": "Горячие клавиши истории",
|
||||
"Keyboard Shortcuts": "Горячие клавиши",
|
||||
"Log Out": "Выйти",
|
||||
"Log Out of Organization": "Выйти из организации",
|
||||
@@ -61,28 +61,28 @@
|
||||
"Mute all sounds from Zulip": "Отключить все звуки от Zulip",
|
||||
"NO": "НЕТ",
|
||||
"Network": "сеть",
|
||||
"OR": "ИЛИ ЖЕ",
|
||||
"OR": "ИЛИ",
|
||||
"Organization URL": "URL организации",
|
||||
"Organizations": "организации",
|
||||
"Organizations": "Организации",
|
||||
"Paste": "Вставить",
|
||||
"Paste and Match Style": "Вставить и соответствовать стилю",
|
||||
"Proxy": "полномочие",
|
||||
"Proxy": "Прокси",
|
||||
"Proxy bypass rules": "Правила обхода прокси",
|
||||
"Proxy rules": "Правила прокси",
|
||||
"Quit": "Уволиться",
|
||||
"Proxy rules": "Правила проксирования",
|
||||
"Quit": "Выйти",
|
||||
"Quit Zulip": "Выйти из Zulip",
|
||||
"Redo": "переделывать",
|
||||
"Redo": "Повторить",
|
||||
"Release Notes": "Примечания к выпуску",
|
||||
"Reload": "перезагружать",
|
||||
"Reload": "Перезагрузить",
|
||||
"Report an Issue": "Сообщить о проблеме",
|
||||
"Reset App Data": "Сбросить данные приложения",
|
||||
"Reset App Settings": "Сбросить настройки приложения",
|
||||
"Reset Application Data": "Сбросить данные приложения",
|
||||
"Save": "Сохранить",
|
||||
"Select All": "Выбрать все",
|
||||
"Settings": "настройки",
|
||||
"Shortcuts": "Ярлыки",
|
||||
"Show App Logs": "Показать журналы приложений",
|
||||
"Settings": "Настройки",
|
||||
"Shortcuts": "Горячие клавиши",
|
||||
"Show App Logs": "Показать журналы приложения",
|
||||
"Show app icon in system tray": "Показать значок приложения в системном трее",
|
||||
"Show app unread badge": "Показать непрочитанный значок приложения",
|
||||
"Show desktop notifications": "Показывать уведомления на рабочем столе",
|
||||
@@ -91,25 +91,25 @@
|
||||
"Start app at login": "Запустить приложение при входе",
|
||||
"Switch to Next Organization": "Переключиться на следующую организацию",
|
||||
"Switch to Previous Organization": "Переключиться на предыдущую организацию",
|
||||
"These desktop app shortcuts extend the Zulip webapp's": "Эти ярлыки настольных приложений расширяют возможности веб-приложения Zulip.",
|
||||
"These desktop app shortcuts extend the Zulip webapp's": "Эти горячие клавиши приложения расширяют возможности Zulip.",
|
||||
"This will delete all application data including all added accounts and preferences": "Это удалит все данные приложения, включая все добавленные учетные записи и настройки",
|
||||
"Tip": "Совет",
|
||||
"Toggle DevTools for Active Tab": "Переключить DevTools для активной вкладки",
|
||||
"Toggle DevTools for Zulip App": "Переключить DevTools для приложения Zulip",
|
||||
"Toggle Do Not Disturb": "Переключить не беспокоить",
|
||||
"Toggle Do Not Disturb": "Переключить в режим не беспокоить",
|
||||
"Toggle Full Screen": "Включить полноэкранный режим",
|
||||
"Toggle Sidebar": "Переключить боковую панель",
|
||||
"Toggle Tray Icon": "Значок переключателя в трее",
|
||||
"Tools": "инструменты",
|
||||
"Undo": "расстегивать",
|
||||
"Toggle Tray Icon": "Переключить Значок в трее",
|
||||
"Tools": "Инструменты",
|
||||
"Undo": "Повторить",
|
||||
"Upload": "Загрузить",
|
||||
"Use system proxy settings (requires restart)": "Использовать настройки системного прокси (требуется перезагрузка)",
|
||||
"View": "Посмотреть",
|
||||
"View Shortcuts": "Посмотреть ярлыки",
|
||||
"View": "Вид",
|
||||
"View Shortcuts": "Посмотреть горячие клавиши окна",
|
||||
"Window": "Окно",
|
||||
"Window Shortcuts": "Ярлыки окон",
|
||||
"Window Shortcuts": "Горячие клавиши окна",
|
||||
"YES": "ДА",
|
||||
"Zoom In": "Приблизить",
|
||||
"Zoom In": "Увеличить",
|
||||
"Zoom Out": "Уменьшить",
|
||||
"Zulip Help": "Zulip Помощь",
|
||||
"keyboard shortcuts": "горячие клавиши",
|
||||
|
8
build/entitlements.mac.plist
Normal file
8
build/entitlements.mac.plist
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@@ -24,4 +24,4 @@ If you'd like to remove organizations and have admin access, you'll need to chan
|
||||
|
||||
It also turns off automatic updates for every Zulip user on the same machine.
|
||||
|
||||
> Currently, we only support `presetOrganizations` and `autoUpdate` settings. We are working on other settings as well, and will update this page when we add support for more.
|
||||
Currently, we only support `presetOrganizations` and `autoUpdate` settings. We are working on other settings as well, and will update this page when we add support for more.
|
||||
|
133
package-lock.json
generated
133
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zulip",
|
||||
"version": "3.1.0-beta",
|
||||
"version": "4.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1712,7 +1712,8 @@
|
||||
"capture-stack-trace": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
|
||||
"integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0="
|
||||
"integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=",
|
||||
"dev": true
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
@@ -2401,6 +2402,7 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
|
||||
"integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"capture-stack-trace": "^1.0.0"
|
||||
}
|
||||
@@ -2876,7 +2878,8 @@
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
|
||||
"dev": true
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.6.0",
|
||||
@@ -5378,7 +5381,8 @@
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
},
|
||||
"get-value": {
|
||||
"version": "2.0.6",
|
||||
@@ -5649,79 +5653,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"google-translate-api": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/google-translate-api/-/google-translate-api-2.3.0.tgz",
|
||||
"integrity": "sha1-YmcwoSPaDVevNzXdcHzacc7pGcc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"configstore": "^2.0.0",
|
||||
"got": "^6.3.0",
|
||||
"safe-eval": "^0.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"configstore": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz",
|
||||
"integrity": "sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=",
|
||||
"requires": {
|
||||
"dot-prop": "^3.0.0",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"mkdirp": "^0.5.0",
|
||||
"object-assign": "^4.0.1",
|
||||
"os-tmpdir": "^1.0.0",
|
||||
"osenv": "^0.1.0",
|
||||
"uuid": "^2.0.1",
|
||||
"write-file-atomic": "^1.1.2",
|
||||
"xdg-basedir": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz",
|
||||
"integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=",
|
||||
"requires": {
|
||||
"is-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"google-translate-token": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/google-translate-token/-/google-translate-token-1.0.0.tgz",
|
||||
"integrity": "sha1-vpQ0RXhvAMN2Xewx9JDawhIo0/g=",
|
||||
"requires": {
|
||||
"configstore": "^2.0.0",
|
||||
"got": "^6.3.0"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
|
||||
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
|
||||
"integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.11",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"slide": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"xdg-basedir": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz",
|
||||
"integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=",
|
||||
"requires": {
|
||||
"os-homedir": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"got": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
||||
"integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"create-error-class": "^3.0.0",
|
||||
"duplexer3": "^0.1.4",
|
||||
@@ -5739,7 +5675,8 @@
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||
"dev": true
|
||||
},
|
||||
"grapheme-splitter": {
|
||||
"version": "1.0.4",
|
||||
@@ -6519,7 +6456,8 @@
|
||||
"imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
|
||||
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
|
||||
"dev": true
|
||||
},
|
||||
"indent-string": {
|
||||
"version": "2.1.0",
|
||||
@@ -6914,7 +6852,8 @@
|
||||
"is-obj": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
|
||||
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
|
||||
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
|
||||
"dev": true
|
||||
},
|
||||
"is-obj-prop": {
|
||||
"version": "1.0.0",
|
||||
@@ -6986,7 +6925,8 @@
|
||||
"is-redirect": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
|
||||
"integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
|
||||
"integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.0.4",
|
||||
@@ -7015,12 +6955,14 @@
|
||||
"is-retry-allowed": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz",
|
||||
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ="
|
||||
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-supported-regexp-flag": {
|
||||
"version": "1.0.1",
|
||||
@@ -7666,7 +7608,8 @@
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
"integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8="
|
||||
"integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.3",
|
||||
@@ -7906,6 +7849,7 @@
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
|
||||
"integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
@@ -7913,7 +7857,8 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8169,7 +8114,8 @@
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
@@ -8412,7 +8358,8 @@
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true
|
||||
},
|
||||
"os-locale": {
|
||||
"version": "3.1.0",
|
||||
@@ -8498,12 +8445,14 @@
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
|
||||
"integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-homedir": "^1.0.0",
|
||||
"os-tmpdir": "^1.0.0"
|
||||
@@ -9157,7 +9106,8 @@
|
||||
"prepend-http": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "1.18.2",
|
||||
@@ -9906,7 +9856,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
@@ -10055,7 +10006,8 @@
|
||||
"slide": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
|
||||
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
|
||||
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=",
|
||||
"dev": true
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
@@ -11473,7 +11425,8 @@
|
||||
"timed-out": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
|
||||
"dev": true
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
@@ -11967,7 +11920,8 @@
|
||||
"unzip-response": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
||||
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
|
||||
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
|
||||
"dev": true
|
||||
},
|
||||
"upath": {
|
||||
"version": "1.0.5",
|
||||
@@ -12038,6 +11992,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
|
||||
"integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"prepend-http": "^1.0.1"
|
||||
}
|
||||
|
20
package.json
20
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "zulip",
|
||||
"productName": "Zulip",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.2-beta",
|
||||
"main": "./app/main",
|
||||
"description": "Zulip Desktop App",
|
||||
"license": "Apache-2.0",
|
||||
@@ -43,6 +43,7 @@
|
||||
"test"
|
||||
],
|
||||
"build": {
|
||||
"afterSign": "./scripts/notarize.js",
|
||||
"appId": "org.zulip.zulip-electron",
|
||||
"asar": true,
|
||||
"asarUnpack": [
|
||||
@@ -57,10 +58,15 @@
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"darkModeSupport": true,
|
||||
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
||||
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
||||
"hardenedRuntime": true,
|
||||
"entitlements": "build/entitlements.mac.plist",
|
||||
"entitlementsInherit": "build/entitlements.mac.plist",
|
||||
"gatekeeperAssess": false
|
||||
},
|
||||
"linux": {
|
||||
"category": "Chat;GNOME;GTK;Network;InstantMessaging",
|
||||
"icon": "build/icon.icns",
|
||||
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
|
||||
"description": "Zulip Desktop Client for Linux",
|
||||
"target": [
|
||||
@@ -110,6 +116,13 @@
|
||||
"x64",
|
||||
"ia32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "msi",
|
||||
"arch": [
|
||||
"x64",
|
||||
"ia32"
|
||||
]
|
||||
}
|
||||
],
|
||||
"icon": "build/icon.ico",
|
||||
@@ -140,9 +153,10 @@
|
||||
"cp-file": "5.0.0",
|
||||
"devtron": "1.4.0",
|
||||
"electron": "3.1.10",
|
||||
"electron-builder": "20.40.2",
|
||||
"electron-builder": "20.43.0",
|
||||
"electron-connect": "0.6.2",
|
||||
"electron-debug": "1.4.0",
|
||||
"electron-notarize": "0.2.0",
|
||||
"eslint-config-xo-typescript": "0.14.0",
|
||||
"fs-extra": "8.1.0",
|
||||
"gulp": "4.0.0",
|
||||
|
22
scripts/notarize.js
Normal file
22
scripts/notarize.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const path = require('path');
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config({ path: path.join(__dirname, '/../.env') });
|
||||
|
||||
const { notarize } = require('electron-notarize');
|
||||
|
||||
exports.default = async function notarizing(context) {
|
||||
const { electronPlatformName, appOutDir } = context;
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
|
||||
return await notarize({
|
||||
appBundleId: 'org.zulip.zulip-electron',
|
||||
appPath: `${appOutDir}/${appName}.app`,
|
||||
appleId: process.env.APPLE_ID,
|
||||
appleIdPassword: process.env.APPLE_ID_PASS,
|
||||
});
|
||||
};
|
1
typings.d.ts
vendored
1
typings.d.ts
vendored
@@ -12,6 +12,7 @@ declare module 'escape-html';
|
||||
declare module 'fs-extra';
|
||||
declare module 'wurl';
|
||||
declare module 'i18n';
|
||||
declare module 'backoff';
|
||||
|
||||
interface PageParamsObject {
|
||||
realm_uri: string;
|
||||
|
Reference in New Issue
Block a user