Compare commits

..

1 Commits

Author SHA1 Message Date
Akash Nimare
340da70868 design: Testing new design. 2018-03-07 20:47:44 +05:30
39 changed files with 863 additions and 1981 deletions

7
.gitignore vendored
View File

@@ -7,13 +7,6 @@ node_modules/
# Compiled binary build directory # Compiled binary build directory
dist/ dist/
#snap generated files
snap/parts
snap/prime
snap/snap
snap/stage
snap/*.snap
# Logs # Logs
logs logs
*.log *.log

View File

@@ -52,8 +52,8 @@ const iconPath = () => {
function createMainWindow() { function createMainWindow() {
// Load the previous state with fallback to defaults // Load the previous state with fallback to defaults
const mainWindowState = windowStateKeeper({ const mainWindowState = windowStateKeeper({
defaultWidth: 1100, defaultWidth: 1000,
defaultHeight: 720 defaultHeight: 600
}); });
// Let's keep the window position global so that we can access it in other process // Let's keep the window position global so that we can access it in other process
@@ -71,6 +71,7 @@ function createMainWindow() {
minHeight: 400, minHeight: 400,
webPreferences: { webPreferences: {
plugins: true, plugins: true,
allowDisplayingInsecureContent: true,
nodeIntegration: true nodeIntegration: true
}, },
show: false show: false

View File

@@ -1,7 +1,8 @@
'use strict'; 'use strict';
const os = require('os');
const path = require('path'); const path = require('path');
const { app, shell, BrowserWindow, Menu, dialog } = require('electron'); const { app, shell, BrowserWindow, Menu } = require('electron');
const fs = require('fs-extra'); const fs = require('fs-extra');
@@ -86,7 +87,7 @@ class AppMenu {
} }
}, { }, {
label: 'Toggle Sidebar', label: 'Toggle Sidebar',
accelerator: 'CommandOrControl+Shift+S', accelerator: 'CommandOrControl+S',
click(item, focusedWindow) { click(item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
const newValue = !ConfigUtil.getConfigItem('showSidebar'); const newValue = !ConfigUtil.getConfigItem('showSidebar');
@@ -138,11 +139,13 @@ class AppMenu {
}, { }, {
label: 'Report an Issue...', label: 'Report an Issue...',
click() { click() {
// the goal is to notify the main.html BrowserWindow const body = `
// which may not be the focused window. <!-- Please succinctly describe your issue and steps to reproduce it. -->
BrowserWindow.getAllWindows().forEach(window => { -
window.webContents.send('open-feedback-modal'); ${app.getName()} ${app.getVersion()}
}); Electron ${process.versions.electron}
${process.platform} ${process.arch} ${os.release()}`;
shell.openExternal(`https://github.com/zulip/zulip-electron/issues/new?body=${encodeURIComponent(body)}`);
} }
}]; }];
} }
@@ -385,19 +388,9 @@ class AppMenu {
} }
static resetAppSettings() { static resetAppSettings() {
const resetAppSettingsMessage = 'By proceeding you will be removing all connected organizations and preferences from Zulip.';
// We save App's settings/configurations in following files // We save App's settings/configurations in following files
const settingFiles = ['window-state.json', 'domain.json', 'settings.json']; const settingFiles = ['window-state.json', 'domain.json', 'settings.json'];
dialog.showMessageBox({
type: 'warning',
buttons: ['YES', 'NO'],
defaultId: 0,
message: 'Are you sure?',
detail: resetAppSettingsMessage
}, response => {
if (response === 0) {
settingFiles.forEach(settingFileName => { settingFiles.forEach(settingFileName => {
const getSettingFilesPath = path.join(app.getPath('appData'), appName, settingFileName); const getSettingFilesPath = path.join(app.getPath('appData'), appName, settingFileName);
fs.access(getSettingFilesPath, error => { fs.access(getSettingFilesPath, error => {
@@ -411,8 +404,6 @@ class AppMenu {
}); });
}); });
} }
});
}
setMenu(props) { setMenu(props) {
const tpl = process.platform === 'darwin' ? this.getDarwinTpl(props) : this.getOtherTpl(props); const tpl = process.platform === 'darwin' ? this.getDarwinTpl(props) : this.getOtherTpl(props);

150
app/package-lock.json generated
View File

@@ -1,22 +1,9 @@
{ {
"name": "zulip", "name": "zulip",
"version": "2.0.0", "version": "1.8.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@electron-elements/send-feedback": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@electron-elements/send-feedback/-/send-feedback-1.0.7.tgz",
"integrity": "sha512-3VS5JlAkZi0Ik2xHPdO0ZT3VvtLH7fqY8UXKHiR4BJxJPdoqlPM9Z0YT0uQxSz/xfBjcfCRV1DlnuJ/S3J99ow==",
"requires": {
"@electron-elements/utils": "1.0.3"
}
},
"@electron-elements/utils": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@electron-elements/utils/-/utils-1.0.3.tgz",
"integrity": "sha512-SMIKfu0UrmslHVKDQhOJDE2OeynWnuznkZlhgB5X2V2h+0t00Pq+ekusxBAAXIdZSdnLPlMcH3zZ6TfDq6mbPA=="
},
"@paulcbetts/cld": { "@paulcbetts/cld": {
"version": "2.4.6", "version": "2.4.6",
"resolved": "https://registry.npmjs.org/@paulcbetts/cld/-/cld-2.4.6.tgz", "resolved": "https://registry.npmjs.org/@paulcbetts/cld/-/cld-2.4.6.tgz",
@@ -65,9 +52,9 @@
"integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc=" "integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc="
}, },
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
"requires": { "requires": {
"sprintf-js": "1.0.3" "sprintf-js": "1.0.3"
} }
@@ -164,27 +151,6 @@
"concat-map": "0.0.1" "concat-map": "0.0.1"
} }
}, },
"builder-util-runtime": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-4.2.0.tgz",
"integrity": "sha512-cROCExnJOJvRD58HHcnrrgyRAoDHGZT0hKox0op7vTuuuRC/1JKMXvSR+Hxy7KWy/aEmKu0HfSqMd4znDEqQsA==",
"requires": {
"bluebird-lst": "1.0.5",
"debug": "3.1.0",
"fs-extra-p": "4.5.2",
"sax": "1.2.4"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"cacheable-request": { "cacheable-request": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
@@ -381,25 +347,62 @@
} }
}, },
"electron-updater": { "electron-updater": {
"version": "2.21.4", "version": "2.18.2",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-2.21.4.tgz", "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-2.18.2.tgz",
"integrity": "sha512-x6QSbyxgGR3szIOBtFoCJH0TfgB55AWHaXmilNgorfvpnCdEMQEATxEzLOW0JCzzcB5y3vBrawvmMUEdXwutmA==", "integrity": "sha512-Kl7zK2E5R/EBYZapDUxWEHDE/ybD+Gw9gheqIy4uVSeKWjkkQkit/QpPOK8LaQwbXD5vDawp6lrB7Z0Yoacd2A==",
"requires": { "requires": {
"bluebird-lst": "1.0.5", "bluebird-lst": "1.0.5",
"builder-util-runtime": "4.2.0", "builder-util-runtime": "4.0.5",
"electron-is-dev": "0.3.0", "electron-is-dev": "0.3.0",
"fs-extra-p": "4.5.2", "fs-extra-p": "4.5.0",
"js-yaml": "3.11.0", "js-yaml": "3.10.0",
"lazy-val": "1.0.3", "lazy-val": "1.0.3",
"lodash.isequal": "4.5.0", "lodash.isequal": "4.5.0",
"semver": "5.5.0", "semver": "5.4.1"
"source-map-support": "0.5.4"
}, },
"dependencies": { "dependencies": {
"semver": { "builder-util-runtime": {
"version": "5.5.0", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-4.0.5.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" "integrity": "sha512-NT8AxWH6miZQHnZzaTVjVp1uc6C/mWlxi6GQXKpd4CwyTQd3rT7+poOGrcOhtIiHYCL9VEbRsVfxUAPPsgqJdg==",
"requires": {
"bluebird-lst": "1.0.5",
"debug": "3.1.0",
"fs-extra-p": "4.5.0",
"sax": "1.2.4"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"fs-extra": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "4.0.0",
"universalify": "0.1.1"
}
},
"fs-extra-p": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-4.5.0.tgz",
"integrity": "sha512-V/sdZmV+Yx3+nfXmjRTdBP4mVWCt7hZ0+ZOv+IZo+6fdkBxafaGsI7mYeNv/J3rWyz+mIToCFQORFSwt1bZw8Q==",
"requires": {
"bluebird-lst": "1.0.5",
"fs-extra": "5.0.0"
}
},
"lazy-val": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.3.tgz",
"integrity": "sha512-pjCf3BYk+uv3ZcPzEVM0BFvO9Uw58TmlrU0oG5tTrr9Kcid3+kdKxapH8CjdYmVa2nO5wOoZn2rdvZx2PKj/xg=="
} }
} }
}, },
@@ -473,25 +476,6 @@
"readable-stream": "2.3.4" "readable-stream": "2.3.4"
} }
}, },
"fs-extra": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "4.0.0",
"universalify": "0.1.1"
}
},
"fs-extra-p": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-4.5.2.tgz",
"integrity": "sha512-ZYqFpBdy9w7PsK+vB30j+TnHOyWHm/CJbUq1qqoE8tb71m6qgk5Wa7gp3MYQdlGFxb9vfznF+yD4jcl8l+y91A==",
"requires": {
"bluebird-lst": "1.0.5",
"fs-extra": "5.0.0"
}
},
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -722,11 +706,11 @@
} }
}, },
"js-yaml": { "js-yaml": {
"version": "3.11.0", "version": "3.10.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
"integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
"requires": { "requires": {
"argparse": "1.0.10", "argparse": "1.0.9",
"esprima": "4.0.0" "esprima": "4.0.0"
} }
}, },
@@ -807,11 +791,6 @@
"json-buffer": "3.0.0" "json-buffer": "3.0.0"
} }
}, },
"lazy-val": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.3.tgz",
"integrity": "sha512-pjCf3BYk+uv3ZcPzEVM0BFvO9Uw58TmlrU0oG5tTrr9Kcid3+kdKxapH8CjdYmVa2nO5wOoZn2rdvZx2PKj/xg=="
},
"lodash.assign": { "lodash.assign": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
@@ -1207,7 +1186,7 @@
"semver": { "semver": {
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4="
}, },
"sntp": { "sntp": {
"version": "1.0.9", "version": "1.0.9",
@@ -1225,19 +1204,6 @@
"is-plain-obj": "1.1.0" "is-plain-obj": "1.1.0"
} }
}, },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz",
"integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==",
"requires": {
"source-map": "0.6.1"
}
},
"spawn-rx": { "spawn-rx": {
"version": "2.0.12", "version": "2.0.12",
"resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz", "resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz",

View File

@@ -1,7 +1,7 @@
{ {
"name": "zulip", "name": "zulip",
"productName": "Zulip", "productName": "Zulip",
"version": "2.0.0", "version": "1.8.2",
"description": "Zulip Desktop App", "description": "Zulip Desktop App",
"license": "Apache-2.0", "license": "Apache-2.0",
"copyright": "Kandra Labs, Inc.", "copyright": "Kandra Labs, Inc.",
@@ -26,12 +26,11 @@
"InstantMessaging" "InstantMessaging"
], ],
"dependencies": { "dependencies": {
"@electron-elements/send-feedback": "1.0.7",
"auto-launch": "5.0.1", "auto-launch": "5.0.1",
"electron-is-dev": "0.3.0", "electron-is-dev": "0.3.0",
"electron-log": "2.2.7", "electron-log": "2.2.7",
"electron-spellchecker": "1.1.2", "electron-spellchecker": "1.1.2",
"electron-updater": "2.21.4", "electron-updater": "2.18.2",
"electron-window-state": "4.1.1", "electron-window-state": "4.1.1",
"is-online": "7.0.0", "is-online": "7.0.0",
"node-json-db": "0.7.3", "node-json-db": "0.7.3",

View File

@@ -1,23 +1,19 @@
<!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> </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>
<a class="bug" onclick="linkInBrowser('bug')" href="#">Found bug?</a> <a class="bug" onclick="linkInBrowser('bug')" href="#">Found bug?</a>
</div> </div>
@@ -45,6 +41,5 @@
shell.openExternal(url); shell.openExternal(url);
} }
</script> </script>
<script>require('./js/shared/preventdrag.js')</script>
</body> </body>
</html> </html>

View File

@@ -28,7 +28,7 @@ body {
-webkit-app-region: drag; -webkit-app-region: drag;
overflow: hidden; overflow: hidden;
transition: all 0.5s ease; transition: all 0.5s ease;
z-index: 2; z-index: 1;
} }
.toggle-sidebar div { .toggle-sidebar div {
@@ -45,28 +45,6 @@ body {
transition: all 0.6s ease-out; transition: all 0.6s ease-out;
} }
#view-controls-container {
height: calc(100% - 156px);
overflow-y: hidden;
}
#view-controls-container:hover {
overflow-y: overlay;
}
#view-controls-container::-webkit-scrollbar {
width: 4px;
}
#view-controls-container::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
}
#view-controls-container::-webkit-scrollbar-thumb {
background-color: darkgrey;
outline: 1px solid slategrey;
}
@font-face { @font-face {
font-family: 'Material Icons'; font-family: 'Material Icons';
font-style: normal; font-style: normal;
@@ -143,14 +121,11 @@ body {
} }
.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;
opacity: 0.9;
padding-right: 14px;
} }
.action-button.active i { .action-button.active i {
color: #1c262b; color: #eee;
} }
.tab:first-child { .tab:first-child {
@@ -274,39 +249,28 @@ body {
} }
webview { webview {
opacity: 1;
/* transition: opacity 0.3s ease-in; */ /* transition: opacity 0.3s ease-in; */
flex-grow: 1; flex-grow: 1;
position: absolute;
width: 100%;
height: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
}
webview.download-webview {
z-index: -1;
pointer-events: none;
} }
webview.onload { webview.onload {
transition: opacity 1s cubic-bezier(0.95, 0.05, 0.795, 0.035); transition: opacity 1s cubic-bezier(0.95, 0.05, 0.795, 0.035);
} }
webview.active {
opacity: 1;
z-index: 1;
visibility: visible;
}
webview.disabled { webview.disabled {
flex: 0 1;
height: 0;
width: 0;
opacity: 0; opacity: 0;
transition: opacity 0.3s ease-out;
} }
webview.focus { webview:focus {
outline: 0px solid transparent; outline: 0px solid transparent;
} }
/* Tooltip styling */ /* Tooltip styling */
#back-tooltip, #back-tooltip,
@@ -314,7 +278,7 @@ webview.focus {
#setting-tooltip { #setting-tooltip {
font-family: sans-serif; font-family: sans-serif;
background: #222c31; background: #222c31;
margin-left: 48px; margin-left: 45px;
padding: 6px 8px; padding: 6px 8px;
position: absolute; position: absolute;
margin-top: 0px; margin-top: 0px;
@@ -386,8 +350,6 @@ webview.focus {
height: 100%; height: 100%;
width: 100%; width: 100%;
position: relative; position: relative;
flex-grow: 1;
flex-basis: 0px;
} }
.hidden { .hidden {
@@ -430,26 +392,3 @@ webview.focus {
opacity: 1; opacity: 1;
} }
} }
send-feedback {
width: 60%;
height: 85%;
}
#feedback-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 67, 67, 0.81);
align-items: center;
justify-content: center;
z-index: 2;
transition: all 1s ease-out;
}
#feedback-modal.show {
display: flex;
}

View File

@@ -95,13 +95,11 @@ td:nth-child(odd) {
} }
#sidebar { #sidebar {
width: 150px; width: 80px;
min-width: 100px; padding: 30px;
padding: 30px 30px 30px 35px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: 16px; font-size: 16px;
background: #f2f2f2;
} }
#nav-container { #nav-container {
@@ -115,7 +113,7 @@ td:nth-child(odd) {
} }
.nav.active { .nav.active {
color: #4ebfac; color: #464e5a;
cursor: default; cursor: default;
position: relative; position: relative;
} }
@@ -123,19 +121,12 @@ td:nth-child(odd) {
.nav.active::before { .nav.active::before {
background: #464e5a; background: #464e5a;
width: 3px; width: 3px;
height: 18px; height: 16px;
position: absolute; position: absolute;
left: -8px; left: -8px;
content: ''; content: '';
} }
/* We don't want to show this in nav item since we have the + button for adding an Organization */
#nav-AddServer {
display: none;
}
#settings-header { #settings-header {
font-size: 22px; font-size: 22px;
color: #222c31; color: #222c31;
@@ -151,12 +142,12 @@ td:nth-child(odd) {
} }
#new-server-container { #new-server-container {
padding-left: 42px; opacity: 1;
padding-top: 25px; transition: opacity 0.3s;
margin-right: 16px;
} }
.title { .title {
padding: 4px 0 6px 0;
font-weight: 500; font-weight: 500;
color: #222c31; color: #222c31;
} }
@@ -168,16 +159,6 @@ td:nth-child(odd) {
padding: 4px 0 6px 0; padding: 4px 0 6px 0;
} }
.add-server-info-row {
display: flex;
margin: 8px 0 0 0;
}
.add-server-info-right {
flex-grow: 1;
margin-top: 10px;
}
.sub-title { .sub-title {
padding: 4px 0 6px 0; padding: 4px 0 6px 0;
font-weight: bold; font-weight: bold;
@@ -188,40 +169,20 @@ img.server-info-icon {
width: 36px; width: 36px;
height: 36px; height: 36px;
padding: 4px; padding: 4px;
cursor: pointer;
vertical-align: middle;
} }
.server-info-left { .server-info-left {
margin: 4px 20px 0 0; margin: 10px 20px 0 0;
min-width: 40%;
} }
.server-info-right { .server-info-right {
margin-top: 4px;
width: 55%;
display: flex;
align-items: baseline;
justify-content: space-between;
flex-grow: 1; flex-grow: 1;
margin-right: 10px;
} }
.server-info-row { .server-info-row {
display: inline-block; display: flex;
margin: 5px 0 0 0; margin: 8px 0 0 0;
}
.server-info-left .server-info-row {
display: inline-flex;
align-items: inherit;
vertical-align: -2px;
position: relative;
}
.server-url {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
.server-info-alias { .server-info-alias {
@@ -229,10 +190,6 @@ img.server-info-icon {
cursor: pointer; cursor: pointer;
} }
.server-url-info {
margin-right: 10px;
}
.setting-input-key { .setting-input-key {
font-size: 14px; font-size: 14px;
height: 27px; height: 27px;
@@ -246,16 +203,18 @@ img.server-info-icon {
.setting-input-value { .setting-input-value {
flex-grow: 1; flex-grow: 1;
font-size: 14px; font-size: 14px;
height: 22px;
border-radius: 3px; border-radius: 3px;
padding: 13px; padding: 7px;
border: #ededed 2px solid; border: #ededed 2px solid;
outline-width: 0; outline-width: 0;
background: transparent; background: transparent;
max-width: 450px; max-width: 500px;
} }
.setting-input-value:focus { .setting-input-value:focus {
border: #4EBFAC 2px solid; border: #7cb980 2px solid;
border-radius: 3px;
} }
.setting-block { .setting-block {
@@ -311,7 +270,8 @@ img.server-info-icon {
} }
.settings-card:hover { .settings-card:hover {
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 0px 0px rgba(0, 0, 0, 0.12); /* border-left: 8px solid #bcbcbc; */
/* box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 0px 0px rgba(0, 0, 0, 0.12); */
} }
.hidden { .hidden {
@@ -320,15 +280,11 @@ img.server-info-icon {
} }
.red { .red {
color: #ef5350; color: #ffffff;
padding: 8px; background: #ef5350;
border: rgba(239, 83, 80, 0.5) solid 1px; padding: 3px;
} padding-right: 10px;
padding-left: 10px;
.red:hover {
color: #e63431;
border: rgba(239, 83, 80, 0.7) solid 1px;
;
} }
.blue { .blue {
@@ -358,8 +314,8 @@ img.server-info-icon {
} }
i.open-tab-button { i.open-tab-button {
padding-left: 2px; padding: 0 5px;
font-size: 19px; font-size: 18px;
cursor: pointer; cursor: pointer;
} }
@@ -412,10 +368,17 @@ i.open-tab-button {
} }
#open-create-org-link { #open-create-org-link {
color: #666;
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
} }
#open-create-org-link:hover {
color: #005580;
;
text-decoration: underline;
}
.toggle { .toggle {
position: absolute; position: absolute;
margin-left: -9999px; margin-left: -9999px;
@@ -470,94 +433,6 @@ input.toggle-round:checked+label:after {
} }
/* Add new server modal */
.add-server-modal {
display: block;
position: fixed;
z-index: 1;
padding-top: 15vh;
left: 0;
top: 0;
margin: auto;
width: 100%;
height: 100%;
/* background: rgba(61, 64, 67, 15); */
background: linear-gradient(35deg, #003b52, #45b59b);
overflow: auto;
}
/* Modal Content */
.modal-container {
background-color: #f4f7f8;
margin: auto;
padding: 57px;
border: #dae1e3 1px solid;
width: 550px;
height: 370px;
border-radius: 4px;
}
.add-server-modal .page-title {
text-align: center;
font-size: 1.6rem;
}
.divider {
margin-bottom: 30px;
margin-top: 30px;
color: #7d878a;
}
.divider hr {
margin-left: 8px;
margin-right: 8px;
width: 44%;
}
.left {
float: left;
}
.right {
float: right;
}
.server-center {
width: 100%;
text-align: center;
align-items: center;
padding-top: 13px;
margin-left: -5px;
}
.server-center button {
font-weight: bold;
font-size: 1.1rem;
margin: auto;
align-items: center;
text-align: center;
color: #fff;
background: #4EBFAC;
border-color: none;
border: none;
width: 98%;
height: 46px;
border-radius: 3px;
cursor: pointer;
}
.server-center button:hover {
background: #329588;
}
.server-center button:focus {
background: #329588;
}
/* responsive grid */ /* responsive grid */
@media (max-width: 650px) { @media (max-width: 650px) {
@@ -571,53 +446,3 @@ input.toggle-round:checked+label:after {
display: none; display: none;
} }
} }
@media (max-width: 720px) {
.modal-container {
width: 60vw;
padding: 40px;
min-width: 300px;
}
.server-center button {
margin-right: -12px;
width: 100%;
}
.divider {
margin-right: -8px;
}
.divider hr {
margin-left: 6px;
margin-right: 6px;
width: 43%;
}
#new-server-container {
padding-left: 0px;
}
}
@media (max-width: 600px) {
.divider {
margin-left: 4%;
}
.divider hr {
margin-left: 2px;
margin-right: 2px;
width: 40%;
}
}
@media (max-width: 900px) {
.settings-card {
flex-direction: column;
align-items: center;
}
.server-info-right {
flex-direction: column;
align-items: center;
}
.action {
margin-top: 10px;
}
}

View File

@@ -1,36 +0,0 @@
const { shell } = require('electron').remote;
const LinkUtil = require('../utils/link-util');
const DomainUtil = require('../utils/domain-util');
const hiddenWebView = require('../components/hidden-webview');
function handleExternalLink(event) {
const { url } = event;
const domainPrefix = DomainUtil.getDomain(this.props.index).url;
// Whitelist URLs which are allowed to be opened in the app
const {
isInternalUrl: isWhiteListURL,
isUploadsUrl: isUploadsURL
} = LinkUtil.isInternal(domainPrefix, url);
if (isWhiteListURL) {
event.preventDefault();
// only open the pdf, mp3, mp4 etc.. in hidden webview since opening the
// image in webview will do nothing and will not save it
// whereas the pdf will be saved to user desktop once openened in
// in the hidden webview and will not trigger webview reload
if (!LinkUtil.isImage(url) && isUploadsURL) {
hiddenWebView.loadURL(url);
return;
}
// open internal urls inside the current webview.
this.$el.loadURL(url);
} else {
event.preventDefault();
shell.openExternal(url);
}
}
module.exports = handleExternalLink;

View File

@@ -1,9 +0,0 @@
// this hidden webview will be used to open pdf url and
// save it to user's computer without triggering a reload
// when navigating to pdf url to download it.
const hiddenWebView = document.createElement('webview');
hiddenWebView.classList.add('download-webview');
hiddenWebView.src = 'about:blank';
document.querySelector('#webviews-container').appendChild(hiddenWebView);
module.exports = hiddenWebView;

View File

@@ -3,12 +3,13 @@
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const DomainUtil = require(__dirname + '/../utils/domain-util.js');
const ConfigUtil = require(__dirname + '/../utils/config-util.js'); const ConfigUtil = require(__dirname + '/../utils/config-util.js');
const SystemUtil = require(__dirname + '/../utils/system-util.js'); const SystemUtil = require(__dirname + '/../utils/system-util.js');
const { app, dialog } = require('electron').remote; const LinkUtil = require(__dirname + '/../utils/link-util.js');
const { shell, app, dialog } = require('electron').remote;
const BaseComponent = require(__dirname + '/../components/base.js'); const BaseComponent = require(__dirname + '/../components/base.js');
const handleExternalLink = require(__dirname + '/../components/handle-external-link.js');
const shouldSilentWebview = ConfigUtil.getConfigItem('silent'); const shouldSilentWebview = ConfigUtil.getConfigItem('silent');
class WebView extends BaseComponent { class WebView extends BaseComponent {
@@ -45,7 +46,16 @@ class WebView extends BaseComponent {
registerListeners() { registerListeners() {
this.$el.addEventListener('new-window', event => { this.$el.addEventListener('new-window', event => {
handleExternalLink.call(this, event); const { url } = event;
const domainPrefix = DomainUtil.getDomain(this.props.index).url;
if (LinkUtil.isInternal(domainPrefix, url) || url === (domainPrefix + '/')) {
event.preventDefault();
this.$el.loadURL(url);
} else {
event.preventDefault();
shell.openExternal(url);
}
}); });
if (shouldSilentWebview) { if (shouldSilentWebview) {
@@ -120,7 +130,6 @@ class WebView extends BaseComponent {
} }
this.$el.classList.remove('disabled'); this.$el.classList.remove('disabled');
this.$el.classList.add('active');
setTimeout(() => { setTimeout(() => {
if (this.props.role === 'server') { if (this.props.role === 'server') {
this.$el.classList.remove('onload'); this.$el.classList.remove('onload');
@@ -159,7 +168,6 @@ class WebView extends BaseComponent {
hide() { hide() {
this.$el.classList.add('disabled'); this.$el.classList.add('disabled');
this.$el.classList.remove('active');
} }
load() { load() {

View File

@@ -1,62 +0,0 @@
const { app } = require('electron').remote;
const path = require('path');
const fs = require('fs');
const SendFeedback = require('@electron-elements/send-feedback');
// make the button color match zulip app's theme
SendFeedback.customStyles = `
button:hover, button:focus {
border-color: #4EBFAC;
color: #4EBFAC;
}
button:active {
background-color: #f1f1f1;
color: #4EBFAC;
}
button {
background-color: #4EBFAC;
border-color: #4EBFAC;
}
`;
customElements.define('send-feedback', SendFeedback);
const sendFeedback = document.querySelector('send-feedback');
const feedbackHolder = sendFeedback.parentElement;
// customize the fields of custom elements
sendFeedback.title = 'Report Issue';
sendFeedback.titleLabel = 'Issue title:';
sendFeedback.titlePlaceholder = 'Enter issue title';
sendFeedback.textareaLabel = 'Describe the issue:';
sendFeedback.textareaPlaceholder = 'Succinctly describe your issue and steps to reproduce it...';
sendFeedback.buttonLabel = 'Report Issue';
sendFeedback.loaderSuccessText = '';
sendFeedback.useReporter('emailReporter', {
email: 'akash@zulipchat.com'
});
feedbackHolder.addEventListener('click', e => {
// only remove the class if the grey out faded
// part is clicked and not the feedback element itself
if (e.target === e.currentTarget) {
feedbackHolder.classList.remove('show');
}
});
sendFeedback.addEventListener('feedback-submitted', () => {
setTimeout(() => {
feedbackHolder.classList.remove('show');
}, 1000);
});
const dataDir = app.getPath('userData');
const logsDir = path.join(dataDir, '/Logs');
sendFeedback.logs.push(...fs.readdirSync(logsDir).map(file => path.join(logsDir, file)));
module.exports = {
feedbackHolder,
sendFeedback
};

View File

@@ -12,7 +12,6 @@ const ServerTab = require(__dirname + '/js/components/server-tab.js');
const FunctionalTab = require(__dirname + '/js/components/functional-tab.js'); const FunctionalTab = require(__dirname + '/js/components/functional-tab.js');
const ConfigUtil = require(__dirname + '/js/utils/config-util.js'); const ConfigUtil = require(__dirname + '/js/utils/config-util.js');
const ReconnectUtil = require(__dirname + '/js/utils/reconnect-util.js'); const ReconnectUtil = require(__dirname + '/js/utils/reconnect-util.js');
const { feedbackHolder } = require(__dirname + '/js/feedback.js');
class ServerManagerView { class ServerManagerView {
constructor() { constructor() {
@@ -123,7 +122,7 @@ class ServerManagerView {
// Remove focus from the settings icon at sidebar bottom // Remove focus from the settings icon at sidebar bottom
this.$settingsButton.classList.remove('active'); this.$settingsButton.classList.remove('active');
} else { } else {
this.openSettings('AddServer'); this.openSettings('Servers');
} }
} }
@@ -160,7 +159,7 @@ class ServerManagerView {
this.tabs[this.activeTabIndex].webview.reload(); this.tabs[this.activeTabIndex].webview.reload();
}); });
this.$addServerButton.addEventListener('click', () => { this.$addServerButton.addEventListener('click', () => {
this.openSettings('AddServer'); this.openSettings('Servers');
}); });
this.$settingsButton.addEventListener('click', () => { this.$settingsButton.addEventListener('click', () => {
this.openSettings('General'); this.openSettings('General');
@@ -176,7 +175,7 @@ class ServerManagerView {
}); });
}); });
this.sidebarHoverEvent(this.$addServerButton, this.$addServerTooltip, true); this.sidebarHoverEvent(this.$addServerButton, this.$addServerTooltip);
this.sidebarHoverEvent(this.$settingsButton, this.$settingsTooltip); this.sidebarHoverEvent(this.$settingsButton, this.$settingsTooltip);
this.sidebarHoverEvent(this.$reloadButton, this.$reloadTooltip); this.sidebarHoverEvent(this.$reloadButton, this.$reloadTooltip);
this.sidebarHoverEvent(this.$backButton, this.$backTooltip); this.sidebarHoverEvent(this.$backButton, this.$backTooltip);
@@ -188,17 +187,9 @@ class ServerManagerView {
return currentIndex; return currentIndex;
} }
sidebarHoverEvent(SidebarButton, SidebarTooltip, addServer = false) { sidebarHoverEvent(SidebarButton, SidebarTooltip) {
SidebarButton.addEventListener('mouseover', () => { SidebarButton.addEventListener('mouseover', () => {
SidebarTooltip.removeAttribute('style'); SidebarTooltip.removeAttribute('style');
// To handle position of add server tooltip due to scrolling of list of organizations
// This could not be handled using CSS, hence the top of the tooltip is made same
// as that of its parent element.
// This needs to handled only for the add server tooltip and not others.
if (addServer) {
const { top } = SidebarButton.getBoundingClientRect();
SidebarTooltip.style.top = top + 'px';
}
}); });
SidebarButton.addEventListener('mouseout', () => { SidebarButton.addEventListener('mouseout', () => {
SidebarTooltip.style.display = 'none'; SidebarTooltip.style.display = 'none';
@@ -208,11 +199,6 @@ class ServerManagerView {
onHover(index, serverName) { onHover(index, serverName) {
this.$serverIconTooltip[index].innerHTML = serverName; this.$serverIconTooltip[index].innerHTML = serverName;
this.$serverIconTooltip[index].removeAttribute('style'); this.$serverIconTooltip[index].removeAttribute('style');
// To handle position of servers' tooltip due to scrolling of list of organizations
// This could not be handled using CSS, hence the top of the tooltip is made same
// as that of its parent element.
const { top } = this.$serverIconTooltip[index].parentElement.getBoundingClientRect();
this.$serverIconTooltip[index].style.top = top + 'px';
} }
onHoverOut(index) { onHoverOut(index) {
@@ -282,10 +268,10 @@ class ServerManagerView {
} }
activateLastTab(index) { activateLastTab(index) {
// Open all the tabs in background, also activate the tab based on the index // Open last active tab
this.activateTab(index);
// Save last active tab
ConfigUtil.setConfigItem('lastActiveTab', index); ConfigUtil.setConfigItem('lastActiveTab', index);
// Open all the tabs in background
this.activateTab(index);
} }
activateTab(index, hideOldTab = true) { activateTab(index, hideOldTab = true) {
@@ -325,7 +311,7 @@ class ServerManagerView {
webContents.send('toggle-sidebar', state); webContents.send('toggle-sidebar', state);
}); });
ipcRenderer.on('toggle-silent', (event, state) => { ipcRenderer.on('toogle-silent', (event, state) => {
const webviews = document.querySelectorAll('webview'); const webviews = document.querySelectorAll('webview');
webviews.forEach(webview => { webviews.forEach(webview => {
try { try {
@@ -510,10 +496,6 @@ class ServerManagerView {
} }
ipcRenderer.send('update-taskbar-icon', createOverlayIcon(messageCount).toDataURL(), String(messageCount)); ipcRenderer.send('update-taskbar-icon', createOverlayIcon(messageCount).toDataURL(), String(messageCount));
}); });
ipcRenderer.on('open-feedback-modal', () => {
feedbackHolder.classList.add('show');
});
} }
} }

View File

@@ -3,8 +3,9 @@
const BaseSection = require(__dirname + '/base-section.js'); const BaseSection = require(__dirname + '/base-section.js');
const DomainUtil = require(__dirname + '/../../utils/domain-util.js'); const DomainUtil = require(__dirname + '/../../utils/domain-util.js');
const ServerInfoForm = require(__dirname + '/server-info-form.js'); const ServerInfoForm = require(__dirname + '/server-info-form.js');
const CreateOrganziation = require(__dirname + '/create-new-org.js');
class ConnectedOrgSection extends BaseSection { class AddedSection extends BaseSection {
constructor(props) { constructor(props) {
super(); super();
this.props = props; this.props = props;
@@ -13,9 +14,10 @@ class ConnectedOrgSection extends BaseSection {
template() { template() {
return ` return `
<div class="settings-pane" id="server-settings-pane"> <div class="settings-pane" id="server-settings-pane">
<div class="page-title">Connected organizations</div> <div id="new-server-container"></div>
<div class="title" id="existing-servers">All the connected orgnizations will appear here.</div> <div class="title" id="existing-servers"></div>
<div id="server-info-container"></div> <div id="server-info-container"></div>
<div id="create-organization-container"></div>
</div> </div>
`; `;
} }
@@ -32,9 +34,12 @@ class ConnectedOrgSection extends BaseSection {
this.$serverInfoContainer = document.getElementById('server-info-container'); this.$serverInfoContainer = document.getElementById('server-info-container');
this.$existingServers = document.getElementById('existing-servers'); this.$existingServers = document.getElementById('existing-servers');
const noServerText = 'All the connected orgnizations will appear here'; this.$serverInfoContainer.innerHTML = servers.length ? '' : '';
// Show noServerText if no servers are there otherwise hide it // Show Existing servers if servers are there otherwise hide it
this.$existingServers.innerHTML = servers.length === 0 ? noServerText : ''; this.$existingServers.innerHTML = servers.length === 0 ? '' : 'Connected organizations';
this.$createOrganizationContainer = document.getElementById('create-organization-container');
this.initCreateNewOrganization();
for (let i = 0; i < servers.length; i++) { for (let i = 0; i < servers.length; i++) {
new ServerInfoForm({ new ServerInfoForm({
@@ -46,6 +51,11 @@ class ConnectedOrgSection extends BaseSection {
} }
} }
initCreateNewOrganization() {
new CreateOrganziation({
$root: this.$createOrganizationContainer
}).init();
}
} }
module.exports = ConnectedOrgSection; module.exports = AddedSection;

View File

@@ -0,0 +1,37 @@
'use strict';
const BaseComponent = require(__dirname + '/../../components/base.js');
const shell = require('electron').shell;
class CreateOrganziation extends BaseComponent {
constructor(props) {
super();
this.props = props;
}
template() {
return `
<div class="setting-row">
<div class="setting-description">
<span id="open-create-org-link">Or create a new organization on zulipchat.com<i class="material-icons open-tab-button">open_in_new</i></span>
</div>
<div class="setting-control"></div>
</div>
`;
}
init() {
this.props.$root.innerHTML = this.template();
this.openCreateNewOrgExternalLink();
}
openCreateNewOrgExternalLink() {
const link = 'https://zulipchat.com/beta/';
const externalCreateNewOrgEl = document.getElementById('open-create-org-link');
externalCreateNewOrgEl.addEventListener('click', () => {
shell.openExternal(link);
});
}
}
module.exports = CreateOrganziation;

View File

@@ -180,7 +180,7 @@ class GeneralSection extends BaseSection {
const newValue = !ConfigUtil.getConfigItem('silent', true); const newValue = !ConfigUtil.getConfigItem('silent', true);
ConfigUtil.setConfigItem('silent', newValue); ConfigUtil.setConfigItem('silent', newValue);
this.updateSilentOption(); this.updateSilentOption();
currentBrowserWindow.send('toggle-silent', newValue); currentBrowserWindow.send('toogle-silent', newValue);
} }
}); });
} }

View File

@@ -8,7 +8,7 @@ class PreferenceNav extends BaseComponent {
this.props = props; this.props = props;
this.navItems = ['General', 'Network', 'AddServer', 'Organizations', 'Shortcuts']; this.navItems = ['General', 'Network', 'Servers', 'Added-servers', 'Shortcuts'];
this.init(); this.init();
} }

View File

@@ -2,7 +2,6 @@
const BaseComponent = require(__dirname + '/../../components/base.js'); const BaseComponent = require(__dirname + '/../../components/base.js');
const DomainUtil = require(__dirname + '/../../utils/domain-util.js'); const DomainUtil = require(__dirname + '/../../utils/domain-util.js');
const shell = require('electron').shell;
class NewServerForm extends BaseComponent { class NewServerForm extends BaseComponent {
constructor(props) { constructor(props) {
@@ -12,24 +11,25 @@ class NewServerForm extends BaseComponent {
template() { template() {
return ` return `
<div class="server-input-container"> <div class="settings-card">
<div class="server-info-right">
<div class="title">Organization URL</div> <div class="title">Organization URL</div>
<div class="add-server-info-row"> <div class="server-info-row">
<input class="setting-input-value" autofocus placeholder="your-organization.zulipchat.com or zulip.your-organization.com"/> <input class="setting-input-value" autofocus placeholder="example.zulipchat.com or chat.example.com"/>
</div>
<div class="server-info-row">
<div class="action blue server-save-action">
<span>Next</span>
</div> </div>
<div class="server-center">
<div class="server-save-action">
<button id="connect">Connect</button>
</div> </div>
</div> </div>
<div class="server-center">
<div class="divider"> <div class="divider">
<hr class="left"/>OR<hr class="right" /> <hr class="left"/>OR<hr class="right" />
</div> </div>
</div>
<div class="server-center"> <div class="server-info-row">
<div class="server-save-action"> <div class="action blue server-create-action">
<button id="open-create-org-link">Create a new organization</button> <span>Create a new organization</span>
</div> </div>
</div> </div>
</div> </div>
@@ -51,25 +51,17 @@ class NewServerForm extends BaseComponent {
} }
submitFormHandler() { submitFormHandler() {
this.$saveServerButton.children[0].innerHTML = 'Connecting...'; this.$saveServerButton.children[0].innerHTML = 'Adding...';
DomainUtil.checkDomain(this.$newServerUrl.value).then(serverConf => { DomainUtil.checkDomain(this.$newServerUrl.value).then(serverConf => {
DomainUtil.addDomain(serverConf).then(() => { DomainUtil.addDomain(serverConf).then(() => {
this.props.onChange(this.props.index); this.props.onChange(this.props.index);
}); });
}, errorMessage => { }, errorMessage => {
this.$saveServerButton.children[0].innerHTML = 'Connect'; this.$saveServerButton.children[0].innerHTML = 'Next';
alert(errorMessage); alert(errorMessage);
}); });
} }
openCreateNewOrgExternalLink() {
const link = 'https://zulipchat.com/new/';
const externalCreateNewOrgEl = document.getElementById('open-create-org-link');
externalCreateNewOrgEl.addEventListener('click', () => {
shell.openExternal(link);
});
}
initActions() { initActions() {
this.$saveServerButton.addEventListener('click', () => { this.$saveServerButton.addEventListener('click', () => {
this.submitFormHandler(); this.submitFormHandler();
@@ -81,8 +73,6 @@ class NewServerForm extends BaseComponent {
this.submitFormHandler(); this.submitFormHandler();
} }
}); });
// open create new org link in default browser
this.openCreateNewOrgExternalLink();
} }
} }

View File

@@ -7,8 +7,8 @@ const Nav = require(__dirname + '/js/pages/preference/nav.js');
const ServersSection = require(__dirname + '/js/pages/preference/servers-section.js'); const ServersSection = require(__dirname + '/js/pages/preference/servers-section.js');
const GeneralSection = require(__dirname + '/js/pages/preference/general-section.js'); const GeneralSection = require(__dirname + '/js/pages/preference/general-section.js');
const NetworkSection = require(__dirname + '/js/pages/preference/network-section.js'); const NetworkSection = require(__dirname + '/js/pages/preference/network-section.js');
const ConnectedOrgSection = require(__dirname + '/js/pages/preference/connected-org-section.js');
const ShortcutsSection = require(__dirname + '/js/pages/preference/shortcuts-section.js'); const ShortcutsSection = require(__dirname + '/js/pages/preference/shortcuts-section.js');
const AddedSection = require(__dirname + '/js/pages/preference/added-server-section.js');
class PreferenceView extends BaseComponent { class PreferenceView extends BaseComponent {
constructor() { constructor() {
@@ -40,7 +40,7 @@ class PreferenceView extends BaseComponent {
handleNavigation(navItem) { handleNavigation(navItem) {
this.nav.select(navItem); this.nav.select(navItem);
switch (navItem) { switch (navItem) {
case 'AddServer': { case 'Servers': {
this.section = new ServersSection({ this.section = new ServersSection({
$root: this.$settingsContainer $root: this.$settingsContainer
}); });
@@ -52,14 +52,14 @@ class PreferenceView extends BaseComponent {
}); });
break; break;
} }
case 'Organizations': { case 'Network': {
this.section = new ConnectedOrgSection({ this.section = new NetworkSection({
$root: this.$settingsContainer $root: this.$settingsContainer
}); });
break; break;
} }
case 'Network': { case 'Added-servers': {
this.section = new NetworkSection({ this.section = new AddedSection({
$root: this.$settingsContainer $root: this.$settingsContainer
}); });
break; break;

View File

@@ -16,18 +16,19 @@ class ServerInfoForm extends BaseComponent {
<div class="settings-card"> <div class="settings-card">
<div class="server-info-left"> <div class="server-info-left">
<img class="server-info-icon" src="${this.props.server.icon}"/> <img class="server-info-icon" src="${this.props.server.icon}"/>
</div>
<div class="server-info-right">
<div class="server-info-row"> <div class="server-info-row">
<span class="server-info-alias">${this.props.server.alias}</span> <span class="server-info-alias">${this.props.server.alias}</span>
<i class="material-icons open-tab-button">open_in_new</i> <i class="material-icons open-tab-button">open_in_new</i>
</div> </div>
</div> <div class="server-info-row">
<div class="server-info-right"> <input class="setting-input-value" disabled value="${this.props.server.url}"/>
<div class="server-info-row server-url">
<span class="server-url-info" title="${this.props.server.url}">${this.props.server.url}</span>
</div> </div>
<div class="server-info-row"> <div class="server-info-row">
<div class="action red server-delete-action"> <div class="action red server-delete-action">
<span>Disconnect</span> <i class="material-icons">indeterminate_check_box</i>
<span>Delete</span>
</div> </div>
</div> </div>
</div> </div>
@@ -43,7 +44,6 @@ class ServerInfoForm extends BaseComponent {
initForm() { initForm() {
this.$serverInfoForm = this.generateNodeFromTemplate(this.template()); this.$serverInfoForm = this.generateNodeFromTemplate(this.template());
this.$serverInfoAlias = this.$serverInfoForm.getElementsByClassName('server-info-alias')[0]; this.$serverInfoAlias = this.$serverInfoForm.getElementsByClassName('server-info-alias')[0];
this.$serverIcon = this.$serverInfoForm.getElementsByClassName('server-info-icon')[0];
this.$deleteServerButton = this.$serverInfoForm.getElementsByClassName('server-delete-action')[0]; this.$deleteServerButton = this.$serverInfoForm.getElementsByClassName('server-delete-action')[0];
this.$openServerButton = this.$serverInfoForm.getElementsByClassName('open-tab-button')[0]; this.$openServerButton = this.$serverInfoForm.getElementsByClassName('open-tab-button')[0];
this.props.$root.appendChild(this.$serverInfoForm); this.props.$root.appendChild(this.$serverInfoForm);
@@ -71,12 +71,7 @@ class ServerInfoForm extends BaseComponent {
this.$serverInfoAlias.addEventListener('click', () => { this.$serverInfoAlias.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'switch-server-tab', this.props.index); ipcRenderer.send('forward-message', 'switch-server-tab', this.props.index);
}); });
this.$serverIcon.addEventListener('click', () => {
ipcRenderer.send('forward-message', 'switch-server-tab', this.props.index);
});
} }
} }
module.exports = ServerInfoForm; module.exports = ServerInfoForm;

View File

@@ -11,12 +11,14 @@ class ServersSection extends BaseSection {
template() { template() {
return ` return `
<div class="add-server-modal"> <div id="myModal" class="modal">
<div class="modal-container"> <div class="modal-content">
<div class="settings-pane" id="server-settings-pane"> <div class="settings-pane" id="server-settings-pane">
<div class="page-title">Add a Zulip organization</div> <div class="page-title">Add a Zulip organization</div>
<div id="new-server-container"></div> <div id="new-server-container"></div>
</div> </div>
</div> </div>
</div> </div>
`; `;
@@ -30,9 +32,16 @@ class ServersSection extends BaseSection {
this.props.$root.innerHTML = ''; this.props.$root.innerHTML = '';
this.props.$root.innerHTML = this.template(); this.props.$root.innerHTML = this.template();
this.$serverInfoContainer = document.getElementById('server-info-container');
this.$existingServers = document.getElementById('existing-servers');
this.$newServerContainer = document.getElementById('new-server-container'); this.$newServerContainer = document.getElementById('new-server-container');
this.$newServerButton = document.getElementById('new-server-action');
this.initNewServerForm(); this.initNewServerForm();
this.$createOrganizationContainer = document.getElementById('create-organization-container');
} }
initNewServerForm() { initNewServerForm() {

View File

@@ -78,6 +78,14 @@ class ShortcutsSection extends BaseSection {
<td><kbd>${userOSKey}</kbd><kbd>A</kbd></td> <td><kbd>${userOSKey}</kbd><kbd>A</kbd></td>
<td>Select All</td> <td>Select All</td>
</tr> </tr>
<tr>
<td><kbd>${userOSKey}</kbd><kbd>F</kbd></td>
<td>Find</td>
</tr>
<tr>
<td><kbd>${userOSKey}</kbd><kbd>G</kbd></td>
<td>Find Next</td>
</tr>
<tr> <tr>
<td><kbd>Control</kbd><kbd>${userOSKey}</kbd><kbd>Space</kbd></td> <td><kbd>Control</kbd><kbd>${userOSKey}</kbd><kbd>Space</kbd></td>
<td>Emoji & Symbols</td> <td>Emoji & Symbols</td>
@@ -113,7 +121,7 @@ class ShortcutsSection extends BaseSection {
<td>Actual Size</td> <td>Actual Size</td>
</tr> </tr>
<tr> <tr>
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd></td> <td><kbd>${userOSKey}</kbd><kbd>S</kbd></td>
<td>Toggle Sidebar</td> <td>Toggle Sidebar</td>
</tr> </tr>
<tr> <tr>
@@ -248,7 +256,7 @@ class ShortcutsSection extends BaseSection {
<td>Actual Size</td> <td>Actual Size</td>
</tr> </tr>
<tr> <tr>
<td><kbd>${userOSKey}</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd></td> <td><kbd>${userOSKey}</kbd> + <kbd>S</kbd></td>
<td>Toggle Sidebar</td> <td>Toggle Sidebar</td>
</tr> </tr>
<tr> <tr>

View File

@@ -4,14 +4,10 @@ const { ipcRenderer } = require('electron');
const SetupSpellChecker = require('./spellchecker'); const SetupSpellChecker = require('./spellchecker');
const ConfigUtil = require(__dirname + '/utils/config-util.js'); const ConfigUtil = require(__dirname + '/utils/config-util.js');
const LinkUtil = require(__dirname + '/utils/link-util.js');
// eslint-disable-next-line import/no-unassigned-import // eslint-disable-next-line import/no-unassigned-import
require('./notification'); require('./notification');
// Prevent drag and drop event in main process which prevents remote code executaion
require(__dirname + '/shared/preventdrag.js');
const logout = () => { const logout = () => {
// Create the menu for the below // Create the menu for the below
document.querySelector('.dropdown-toggle').click(); document.querySelector('.dropdown-toggle').click();
@@ -24,7 +20,7 @@ const shortcut = () => {
// Create the menu for the below // Create the menu for the below
const node = document.querySelector('a[data-overlay-trigger=keyboard-shortcuts]'); const node = document.querySelector('a[data-overlay-trigger=keyboard-shortcuts]');
// Additional check // Additional check
if (node.text.trim().toLowerCase() === 'keyboard shortcuts (?)') { if (node.text.trim().toLowerCase() === 'keyboard shortcuts') {
node.click(); node.click();
} else { } else {
// Atleast click the dropdown // Atleast click the dropdown
@@ -56,24 +52,6 @@ document.addEventListener('DOMContentLoaded', () => {
ipcRenderer.send('forward-message', 'reload-viewer'); ipcRenderer.send('forward-message', 'reload-viewer');
}); });
} }
// Open image attachment link in the lightbox instead of opening in the default browser
const { $, lightbox } = window;
$('#main_div').on('click', '.message_content p a', function (e) {
const url = $(this).attr('href');
if (LinkUtil.isImage(url)) {
const $img = $(this).parent().siblings('.message_inline_image').find('img');
// prevent the image link from opening in a new page.
e.preventDefault();
// prevent the message compose dialog from happening.
e.stopPropagation();
lightbox.open($img);
}
});
}); });
// Clean up spellchecker events after you navigate away from this page; // Clean up spellchecker events after you navigate away from this page;
@@ -82,10 +60,3 @@ window.addEventListener('beforeunload', () => {
SetupSpellChecker.unsubscribeSpellChecker(); SetupSpellChecker.unsubscribeSpellChecker();
}); });
// electron's globalShortcut can cause unexpected results
// so adding the reload shortcut in the old-school way
document.addEventListener('keydown', event => {
if (event.code === 'F5') {
ipcRenderer.send('forward-message', 'hard-reload');
}
});

View File

@@ -1,17 +0,0 @@
'use strict';
// This is a security fix. Following function prevents drag and drop event in the app
// so that attackers can't execute any remote code within the app
// It doesn't affect the compose box so that users can still
// use drag and drop event to share files etc
const preventDragAndDrop = () => {
const preventEvents = ['dragover', 'drop'];
preventEvents.forEach(dragEvents => {
document.addEventListener(dragEvents, event => {
event.preventDefault();
});
});
};
preventDragAndDrop();

View File

@@ -19,20 +19,7 @@ class LinkUtil {
const currentDomain = wurl('hostname', currentUrl); const currentDomain = wurl('hostname', currentUrl);
const newDomain = wurl('hostname', newUrl); const newDomain = wurl('hostname', newUrl);
const sameDomainUrl = (currentDomain === newDomain || newUrl === currentUrl + '/'); return (currentDomain === newDomain) && newUrl.includes('/#narrow');
const isUploadsUrl = newUrl.includes(currentUrl + '/user_uploads/');
const isInternalUrl = newUrl.includes('/#narrow') || isUploadsUrl;
return {
isInternalUrl: sameDomainUrl && isInternalUrl,
isUploadsUrl
};
}
isImage(url) {
// test for images extension as well as urls like .png?s=100
const isImageUrl = /\.(bmp|gif|jpg|jpeg|png|webp)\?*.*$/i;
return isImageUrl.test(url);
} }
} }

View File

@@ -37,11 +37,9 @@ class ReconnectUtil {
console.log('There is no internet connection, try checking network cables, modem and router.'); console.log('There is no internet connection, try checking network cables, modem and router.');
const errMsgHolder = document.querySelector('#description'); const errMsgHolder = document.querySelector('#description');
if (errMsgHolder) {
errMsgHolder.innerHTML = ` errMsgHolder.innerHTML = `
<div>You internet connection does't seem to work properly!</div> <div>You internet connection does't seem to work properly!</div>
</div>Verify that it works and then click try again.</div>`; </div>Verify that it works and then click try again.</div>`;
}
return resolve(false); return resolve(false);
}); });
} else { } else {

View File

@@ -42,11 +42,6 @@
<div id="webviews-container"></div> <div id="webviews-container"></div>
</div> </div>
</div> </div>
<div id="feedback-modal">
<send-feedback></send-feedback>
</div>
</body> </body>
<script src="js/main.js"></script> <script src="js/main.js"></script>
<script>require('./js/shared/preventdrag.js')</script>
</html> </html>

View File

@@ -18,5 +18,4 @@
</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>
</html> </html>

View File

@@ -1,11 +1,157 @@
<!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">
<style>
/* The Modal (background) */
.modal {
display: block;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
/* background-color: rgb(0, 0, 0); */
/* Fallback color */
/* background-color: rgba(0, 0, 0, 0.4); */
background: rgba(61, 64, 67, 15);
/* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 57px;
border: #dae1e3 1px solid;
width: 600px;
/* margin-bottom: 113px; */
height: 344px;
border-radius: 4px;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
#server-settings-pane {
margin-left: 18%;
}
.settings-card.server-info-right:hover {
box-shadow: none !important;
border: none !important;
}
.server-save-action {
padding: 11px;
padding-left: 20px;
width: 292px;
border-radius: 4px;
margin-top: 16px;
}
.divider {
/* width: 250px;
text-align: center;
margin-left: 39px;
margin-top: 48px; */
width: 335px;
text-align: center;
margin-left: 0px;
margin-top: 48px;
color: #7d878a;
}
.divider hr {
margin-left: auto;
margin-right: auto;
width: 42%;
}
.left {
float: left;
}
.right {
float: right;
}
.server-create-action {
width: 314px;
margin-top: 40px;
padding: 11px;
border-radius: 4px;
}
.server-create-action span {
margin-left: 60px;
font-size: 15px;
}
.server-save-action span {
margin-left: 130px;
}
.server-save-action {
width: 306px;
}
.server-info-row {
display: block;
}
.setting-input-value {
width: 319px;
}
.page-title {
color: #222c31;
margin-left: 65px;
font-size: 22px;
font-weight: 100;
margin-bottom: 20px;
padding: 0;
}
.title {
color: #7d878a;
}
</style>
</head> </head>
<body> <body>
<div id="content"> <div id="content">
<div id="sidebar"></div> <div id="sidebar"></div>
@@ -13,5 +159,5 @@
</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>
</html> </html>

View File

@@ -15,7 +15,6 @@ To build and run the app from source, you'll need the following:
* [Python](https://www.python.org/downloads/release/python-2713/) * [Python](https://www.python.org/downloads/release/python-2713/)
(v2.7.x recommended) (v2.7.x recommended)
* A C++ compiler compatible with C++11 * A C++ compiler compatible with C++11
* Linux users also need [Snapcraft](https://snapcraft.io/)
* Development headers for the libXext, libXtst, and libxkbfile libraries * Development headers for the libXext, libXtst, and libxkbfile libraries
### Debian/Ubuntu and friends ### Debian/Ubuntu and friends
@@ -26,7 +25,7 @@ manager (see [here][nodesource-install] for more on the first command):
```sh ```sh
$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - $ 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 $ sudo apt install git nodejs python build-essential libxext-dev libxtst-dev libxkbfile-dev
``` ```
[nodesource-install]: https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions [nodesource-install]: https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions
@@ -77,7 +76,7 @@ This command will produce distributable packages or installers for the
operating system you're running on: operating system you're running on:
* on Windows, a Windows installer file * on Windows, a Windows installer file
* on macOS, a `.dmg` file * on macOS, a `.dmg` file
* on Linux, a plain `.zip` file as well as a `.deb` file, `.snap` file and an * on Linux, a plain `.zip` file as well as a `.deb` file and an
`AppImage` file. `AppImage` file.
To generate all three types, you will need all three operating To generate all three types, you will need all three operating
systems. systems.

1517
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "zulip", "name": "zulip",
"productName": "Zulip", "productName": "Zulip",
"version": "2.0.0", "version": "1.8.2",
"main": "./app/main", "main": "./app/main",
"description": "Zulip Desktop App", "description": "Zulip Desktop App",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -22,7 +22,7 @@
}, },
"scripts": { "scripts": {
"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": "./tools/reinstall-node-modules",
"postinstall": "electron-builder install-app-deps", "postinstall": "electron-builder install-app-deps",
"test": "xo", "test": "xo",
"test-e2e": "gulp test-e2e", "test-e2e": "gulp test-e2e",
@@ -55,8 +55,7 @@
"target": [ "target": [
"deb", "deb",
"zip", "zip",
"AppImage", "AppImage"
"snap"
], ],
"maintainer": "Akash Nimare <svnitakash@gmail.com>" "maintainer": "Akash Nimare <svnitakash@gmail.com>"
}, },
@@ -65,9 +64,6 @@
"afterInstall": "./scripts/debian-add-repo.sh", "afterInstall": "./scripts/debian-add-repo.sh",
"afterRemove": "./scripts/debian-uninstaller.sh" "afterRemove": "./scripts/debian-uninstaller.sh"
}, },
"snap": {
"synopsis": "Zulip Desktop App"
},
"dmg": { "dmg": {
"background": "build/appdmg.png", "background": "build/appdmg.png",
"icon": "build/icon.icns", "icon": "build/icon.icns",
@@ -117,8 +113,8 @@
"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": "1.8.4", "electron": "1.8.2",
"electron-builder": "20.8.1", "electron-builder": "19.53.6",
"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",
@@ -127,7 +123,7 @@
"is-ci": "^1.0.10", "is-ci": "^1.0.10",
"nodemon": "^1.14.11", "nodemon": "^1.14.11",
"pre-commit": "1.2.2", "pre-commit": "1.2.2",
"spectron": "3.8.0", "spectron": "3.7.2",
"tap-colorize": "^1.2.0", "tap-colorize": "^1.2.0",
"tape": "^4.8.0", "tape": "^4.8.0",
"xo": "0.18.2" "xo": "0.18.2"

View File

@@ -2,10 +2,6 @@
# This script runs when user install the debian package # This script runs when user install the debian package
# Link to the binary
ln -sf '/opt/${productFilename}/${executable}' '/usr/local/bin/${executable}';
echo 'Successfully added /opt/${productFilename}/${executable} to /usr/local/bin/${executable}'
# Install apt repository source list if it does not exist # Install apt repository source list if it does not exist
if ! grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep zulip.list; then if ! grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep zulip.list; then
sudo apt-key adv --keyserver pool.sks-keyservers.net --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9 sudo apt-key adv --keyserver pool.sks-keyservers.net --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9

View File

@@ -29,7 +29,3 @@ appDirectory=/home/$getSudoUser/.config/Zulip/;
if [ -d $appDirectory ]; then if [ -d $appDirectory ]; then
sudo rm -rf $appDirectory; sudo rm -rf $appDirectory;
fi fi
# Delete the link to the binary
echo 'Removing binary link'
sudo rm -f '/usr/local/bin/${executable}';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,37 +0,0 @@
name: zulip
version: 2.0.0
summary: Zulip Desktop Client for Linux
description: Zulip combines the immediacy of Slack with an email threading model. With Zulip, you can catch up on important conversations while ignoring irrelevant ones.
confinement: strict
grade: stable
icon: snap/gui/icon.png
apps:
zulip:
command: env TMPDIR=$XDG_RUNTIME_DIR desktop-launch $SNAP/zulip
plugs:
- desktop
- desktop-legacy
- home
- x11
- unity7
- browser-support
- network
- gsettings
- pulseaudio
- opengl
parts:
app:
plugin: dump
stage-packages:
- libasound2
- libgconf2-4
- libnotify4
- libnspr4
- libnss3
- libpcre3
- libpulse0
- libxss1
- libxtst6
source: dist/linux-unpacked
after:
- desktop-gtk2

View File

@@ -7,7 +7,7 @@ test('app runs', function (t) {
const app = setup.createApp() const app = setup.createApp()
setup.waitForLoad(app, t) setup.waitForLoad(app, t)
.then(() => app.client.windowByIndex(1)) // focus on webview .then(() => app.client.windowByIndex(1)) // focus on webview
.then(() => app.client.waitForExist('//*[@id="connect"]')) // id of the connect button .then(() => app.client.waitForExist('//*[@id="new-server-container"]/div/div/div[2]/input'))
.then(() => setup.endTest(app, t), .then(() => setup.endTest(app, t),
(err) => setup.endTest(app, t, err || 'error')) (err) => setup.endTest(app, t, err || 'error'))
}) })

View File

@@ -1,17 +0,0 @@
const test = require('tape')
const setup = require('./setup')
// Create new org link should open in the default browser [WIP]
test('new-org-link', function (t) {
t.timeoutAfter(50e3)
setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t)
.then(() => app.client.windowByIndex(1)) // focus on webview
.then(() => app.client.click('#open-create-org-link')) // Click on new org link button
.then(() => setup.wait(5000))
.then(() => setup.endTest(app, t),
(err) => setup.endTest(app, t, err || 'error'))
})

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env node
const {exec} = require('child_process');
const path = require('path');
const isWindows = process.platform === 'win32';
const command = path.join(__dirname, `reinstall-node-modules${isWindows ? '.cmd' : ''}`);
const proc = exec(command, error => {
if (error) {
console.error(error);
}
});
proc.stdout.on('data', data => console.log(data.toString()));
proc.stderr.on('data', data => console.error(data.toString()));
proc.on('exit', code => {
process.exit(code);
});