Compare commits

...

25 Commits

Author SHA1 Message Date
Anders Kaseorg
56ab0833b8 release: New release v5.9.4.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-04 16:29:48 -08:00
Anders Kaseorg
c62b393c52 Set quarantine attribute for downloads on macOS.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-04 16:12:31 -08:00
Anders Kaseorg
991de77cad Restore default macOS security settings.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 20:36:13 -08:00
Anders Kaseorg
94780c44c8 handle-external-link: Ignore invalid URLs.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 18:06:36 -08:00
Anders Kaseorg
82542a6390 packaging: Synchronize deb-after-install.sh with upstream.
https://github.com/electron-userland/electron-builder/blob/v23.6.0/packages/app-builder-lib/templates/linux/after-install.tpl

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 17:14:50 -08:00
Anders Kaseorg
53ff8443dc Upgrade dependencies, including Electron 22.0.0.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:17:24 -08:00
Anders Kaseorg
3855ecab58 Disable sandboxing for now.
Sandboxing will default to enabled in Electron ≥ 20, but we don’t
support it yet.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:17:24 -08:00
Anders Kaseorg
a57cbb4aa8 package.json: Bump engines to node ≥ 16.13.2.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
56a4461c2a xo: Fix n/file-extension-in-import, maybe.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
cd023ec5ab xo: Fix @typescript-eslint/consistent-type-definitions.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
1aa4ade3c0 xo: Fix @typescript-eslint/parameter-properties.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
dcb46eef4f xo: Fix @typescript-eslint/no-useless-empty-export.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
e3e8ef6e3e xo: Fix @typescript-eslint/consistent-generic-constructors.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
6808b1971a xo: Fix unicorn/switch-case-braces.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
1dd5269549 xo: Fix unicorn/prefer-node-protocol.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
d33adca1e8 xo: Fix unicorn/prefer-logical-operator-over-ternary.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 16:05:28 -08:00
Anders Kaseorg
8ea7f7864f autoupdater: Add const assertion.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 14:09:17 -08:00
Anders Kaseorg
493ae06e52 Reformat with Prettier.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-01-03 14:08:23 -08:00
Anders Kaseorg
2b8f3536d3 Fix E2E tests broken by chat.zulip.org web-public streams.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-12-14 22:41:35 -08:00
Anders Kaseorg
544d23ec09 how-to-install: Update APT instructions.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-07-15 15:36:41 -07:00
Anders Kaseorg
588d32fd22 release: New release v5.9.3.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-04-28 20:25:15 -07:00
Anders Kaseorg
1c471fe624 Upgrade dependencies, including Electron 18.2.0.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-04-28 20:06:46 -07:00
Anders Kaseorg
52486d687d Allow the autoupdater to quit the app normally.
Forcing it to quit would prematurely terminate the update on some
platforms.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-04-28 19:51:07 -07:00
Anders Kaseorg
73441d791c release: New release v5.9.2.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-04-20 21:23:00 -07:00
Anders Kaseorg
1bb6423721 Upgrade dependencies, including Electron 18.1.0.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2022-04-20 19:26:47 -07:00
62 changed files with 4131 additions and 4677 deletions

View File

@@ -6,10 +6,10 @@ import {JsonDB} from "node-json-db";
import {DataError} from "node-json-db/dist/lib/Errors";
import type * as z from "zod";
import {configSchemata} from "./config-schemata";
import * as EnterpriseUtil from "./enterprise-util";
import Logger from "./logger-util";
import {app, dialog} from "./remote";
import {configSchemata} from "./config-schemata.js";
import * as EnterpriseUtil from "./enterprise-util.js";
import Logger from "./logger-util.js";
import {app, dialog} from "./remote.js";
export type Config = {
[Key in keyof typeof configSchemata]: z.output<typeof configSchemata[Key]>;

View File

@@ -1,6 +1,6 @@
import fs from "node:fs";
import {app} from "./remote";
import {app} from "./remote.js";
let setupCompleted = false;

View File

@@ -2,8 +2,8 @@ import process from "node:process";
import type * as z from "zod";
import type {dndSettingsSchemata} from "./config-schemata";
import * as ConfigUtil from "./config-util";
import type {dndSettingsSchemata} from "./config-schemata.js";
import * as ConfigUtil from "./config-util.js";
export type DndSettings = {
[Key in keyof typeof dndSettingsSchemata]: z.output<
@@ -13,10 +13,10 @@ export type DndSettings = {
type SettingName = keyof DndSettings;
interface Toggle {
type Toggle = {
dnd: boolean;
newSettings: Partial<DndSettings>;
}
};
export function toggle(): Toggle {
const dnd = !ConfigUtil.getConfigItem("dnd", false);

View File

@@ -4,8 +4,8 @@ import process from "node:process";
import * as z from "zod";
import {enterpriseConfigSchemata} from "./config-schemata";
import Logger from "./logger-util";
import {enterpriseConfigSchemata} from "./config-schemata.js";
import Logger from "./logger-util.js";
type EnterpriseConfig = {
[Key in keyof typeof enterpriseConfigSchemata]: z.output<

View File

@@ -3,7 +3,7 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import {html} from "./html";
import {html} from "./html.js";
export async function openBrowser(url: URL): Promise<void> {
if (["http:", "https:", "mailto:"].includes(url.protocol)) {

View File

@@ -1,14 +1,14 @@
import {Console} from "node:console";
import {Console} from "node:console"; // eslint-disable-line n/prefer-global/console
import fs from "node:fs";
import os from "node:os";
import process from "node:process";
import {initSetUp} from "./default-util";
import {app} from "./remote";
import {initSetUp} from "./default-util.js";
import {app} from "./remote.js";
interface LoggerOptions {
type LoggerOptions = {
file?: string;
}
};
initSetUp();

View File

@@ -1,7 +1,7 @@
interface DialogBoxError {
type DialogBoxError = {
title: string;
content: string;
}
};
export function invalidZulipServerError(domain: string): string {
return `${domain} does not appear to be a valid Zulip server. Make sure that

View File

@@ -2,7 +2,7 @@ import path from "node:path";
import i18n from "i18n";
import * as ConfigUtil from "./config-util";
import * as ConfigUtil from "./config-util.js";
i18n.configure({
directory: path.join(__dirname, "../translations/"),
@@ -14,5 +14,5 @@ const appLocale = ConfigUtil.getConfigItem("appLanguage", "en");
/* If no locale present in the json, en is set default */
export function __(phrase: string): string {
return i18n.__({phrase, locale: appLocale ? appLocale : "en"});
return i18n.__({phrase, locale: appLocale ?? "en"});
}

View File

@@ -1,7 +1,7 @@
import type {DndSettings} from "./dnd-util";
import type {MenuProps, ServerConf} from "./types";
import type {DndSettings} from "./dnd-util.js";
import type {MenuProps, ServerConf} from "./types.js";
export interface MainMessage {
export type MainMessage = {
"clear-app-settings": () => void;
"configure-spell-checker": () => void;
"fetch-user-agent": () => string;
@@ -22,15 +22,15 @@ export interface MainMessage {
"update-badge": (messageCount: number) => void;
"update-menu": (props: MenuProps) => void;
"update-taskbar-icon": (data: string, text: string) => void;
}
};
export interface MainCall {
export type MainCall = {
"get-server-settings": (domain: string) => ServerConf;
"is-online": (url: string) => boolean;
"save-server-icon": (iconURL: string) => string;
}
};
export interface RendererMessage {
export type RendererMessage = {
back: () => void;
"copy-zulip-url": () => void;
destroytray: () => void;
@@ -79,4 +79,4 @@ export interface RendererMessage {
zoomActualSize: () => void;
zoomIn: () => void;
zoomOut: () => void;
}
};

View File

@@ -1,8 +1,8 @@
export interface MenuProps {
export type MenuProps = {
tabs: TabData[];
activeTabIndex?: number;
enableMenu?: boolean;
}
};
export type NavItem =
| "General"
@@ -11,16 +11,16 @@ export type NavItem =
| "Organizations"
| "Shortcuts";
export interface ServerConf {
export type ServerConf = {
url: string;
alias: string;
icon: string;
}
};
export type TabRole = "server" | "function";
export interface TabData {
export type TabData = {
role: TabRole;
name: string;
index: number;
}
};

View File

@@ -1,17 +1,20 @@
import {shell} from "electron/common";
import {app, dialog, session} from "electron/main";
import process from "node:process";
import util from "node:util";
import log from "electron-log";
import type {UpdateDownloadedEvent, UpdateInfo} from "electron-updater";
import {autoUpdater} from "electron-updater";
import * as ConfigUtil from "../common/config-util";
import * as ConfigUtil from "../common/config-util.js";
import {linuxUpdateNotification} from "./linuxupdater"; // Required only in case of linux
import {linuxUpdateNotification} from "./linuxupdater.js"; // Required only in case of linux
const sleep = util.promisify(setTimeout);
let quitting = false;
export function shouldQuitForUpdate(): boolean {
return quitting;
}
export async function appUpdater(updateFromMenu = false): Promise<void> {
// Don't initiate auto-updates in development
@@ -37,7 +40,10 @@ export async function appUpdater(updateFromMenu = false): Promise<void> {
autoUpdater.allowPrerelease = isBetaUpdate;
const eventsListenerRemove = ["update-available", "update-not-available"];
const eventsListenerRemove = [
"update-available",
"update-not-available",
] as const;
autoUpdater.on("update-available", async (info: UpdateInfo) => {
if (updateFromMenu) {
updateAvailable = true;
@@ -104,10 +110,8 @@ Current Version: ${app.getVersion()}`,
detail: "It will be installed the next time you restart the application",
});
if (response === 0) {
await sleep(1000);
quitting = true;
autoUpdater.quitAndInstall();
// Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app.
app.quit();
}
});
// Init for updates

View File

@@ -3,9 +3,9 @@ import type {BrowserWindow} from "electron/main";
import {app} from "electron/main";
import process from "node:process";
import * as ConfigUtil from "../common/config-util";
import * as ConfigUtil from "../common/config-util.js";
import {send} from "./typed-ipc-main";
import {send} from "./typed-ipc-main.js";
function showBadgeCount(messageCount: number, mainWindow: BrowserWindow): void {
if (process.platform === "win32") {

View File

@@ -8,10 +8,10 @@ import {Notification, app} from "electron/main";
import fs from "node:fs";
import path from "node:path";
import * as ConfigUtil from "../common/config-util";
import * as LinkUtil from "../common/link-util";
import * as ConfigUtil from "../common/config-util.js";
import * as LinkUtil from "../common/link-util.js";
import {send} from "./typed-ipc-main";
import {send} from "./typed-ipc-main.js";
function isUploadsUrl(server: string, url: URL): boolean {
return url.origin === server && url.pathname.startsWith("/user_uploads/");
@@ -105,7 +105,13 @@ export default function handleExternalLink(
details: HandlerDetails,
mainContents: WebContents,
): void {
const url = new URL(details.url);
let url: URL;
try {
url = new URL(details.url);
} catch {
return;
}
const downloadPath = ConfigUtil.getConfigItem(
"downloadsPath",
`${app.getPath("downloads")}`,

View File

@@ -6,18 +6,20 @@ import process from "node:process";
import * as remoteMain from "@electron/remote/main";
import windowStateKeeper from "electron-window-state";
import * as ConfigUtil from "../common/config-util";
import type {RendererMessage} from "../common/typed-ipc";
import type {MenuProps} from "../common/types";
import * as ConfigUtil from "../common/config-util.js";
import type {RendererMessage} from "../common/typed-ipc.js";
import type {MenuProps} from "../common/types.js";
import {appUpdater} from "./autoupdater";
import * as BadgeSettings from "./badge-settings";
import handleExternalLink from "./handle-external-link";
import * as AppMenu from "./menu";
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request";
import {sentryInit} from "./sentry";
import {setAutoLaunch} from "./startup";
import {ipcMain, send} from "./typed-ipc-main";
import {appUpdater, shouldQuitForUpdate} from "./autoupdater.js";
import * as BadgeSettings from "./badge-settings.js";
import handleExternalLink from "./handle-external-link.js";
import * as AppMenu from "./menu.js";
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request.js";
import {sentryInit} from "./sentry.js";
import {setAutoLaunch} from "./startup.js";
import {ipcMain, send} from "./typed-ipc-main.js";
import "gatemaker/electron-setup"; // eslint-disable-line import/no-unassigned-import
// eslint-disable-next-line @typescript-eslint/naming-convention
const {GDK_BACKEND} = process.env;
@@ -73,6 +75,7 @@ function createMainWindow(): BrowserWindow {
minHeight: 400,
webPreferences: {
preload: require.resolve("../renderer/js/main"),
sandbox: false,
webviewTag: true,
},
show: false,
@@ -91,7 +94,7 @@ function createMainWindow(): BrowserWindow {
app.quit();
}
if (!isQuitting) {
if (!isQuitting && !shouldQuitForUpdate()) {
event.preventDefault();
if (process.platform === "darwin") {

View File

@@ -5,7 +5,7 @@ import path from "node:path";
import {JsonDB} from "node-json-db";
import {DataError} from "node-json-db/dist/lib/Errors";
import Logger from "../common/logger-util";
import Logger from "../common/logger-util.js";
const logger = new Logger({
file: "linux-update-util.log",

View File

@@ -5,11 +5,11 @@ import getStream from "get-stream";
import * as semver from "semver";
import * as z from "zod";
import * as ConfigUtil from "../common/config-util";
import Logger from "../common/logger-util";
import * as ConfigUtil from "../common/config-util.js";
import Logger from "../common/logger-util.js";
import * as LinuxUpdateUtil from "./linux-update-util";
import {fetchResponse} from "./request";
import * as LinuxUpdateUtil from "./linux-update-util.js";
import {fetchResponse} from "./request.js";
const logger = new Logger({
file: "linux-update-util.log",

View File

@@ -5,14 +5,14 @@ import process from "node:process";
import AdmZip from "adm-zip";
import * as ConfigUtil from "../common/config-util";
import * as DNDUtil from "../common/dnd-util";
import * as t from "../common/translation-util";
import type {RendererMessage} from "../common/typed-ipc";
import type {MenuProps, TabData} from "../common/types";
import * as ConfigUtil from "../common/config-util.js";
import * as DNDUtil from "../common/dnd-util.js";
import * as t from "../common/translation-util.js";
import type {RendererMessage} from "../common/typed-ipc.js";
import type {MenuProps, TabData} from "../common/types.js";
import {appUpdater} from "./autoupdater";
import {send} from "./typed-ipc-main";
import {appUpdater} from "./autoupdater.js";
import {send} from "./typed-ipc-main.js";
const appName = app.name;

View File

@@ -9,9 +9,9 @@ import * as Sentry from "@sentry/electron";
import getStream from "get-stream";
import * as z from "zod";
import Logger from "../common/logger-util";
import * as Messages from "../common/messages";
import type {ServerConf} from "../common/types";
import Logger from "../common/logger-util.js";
import * as Messages from "../common/messages.js";
import type {ServerConf} from "../common/types.js";
export async function fetchResponse(
request: ClientRequest,

View File

@@ -2,7 +2,7 @@ import {app} from "electron/main";
import * as Sentry from "@sentry/electron";
import {getConfigItem} from "../common/config-util";
import {getConfigItem} from "../common/config-util.js";
export const sentryInit = (): void => {
Sentry.init({

View File

@@ -3,7 +3,7 @@ import process from "node:process";
import AutoLaunch from "auto-launch";
import * as ConfigUtil from "../common/config-util";
import * as ConfigUtil from "../common/config-util.js";
export const setAutoLaunch = async (
AutoLaunchValue: boolean,

View File

@@ -16,11 +16,11 @@ import crypto from "node:crypto";
// dont leak anything from the users clipboard other than the token
// intended for us.
export interface ClipboardDecrypter {
export type ClipboardDecrypter = {
version: number;
key: Uint8Array;
pasted: Promise<string>;
}
};
export class ClipboardDecrypterImpl implements ClipboardDecrypter {
version: number;

View File

@@ -1,4 +1,4 @@
import type {Html} from "../../../common/html";
import type {Html} from "../../../common/html.js";
export function generateNodeFromHtml(html: Html): Element {
const wrapper = document.createElement("div");

View File

@@ -8,7 +8,7 @@ import process from "node:process";
import {Menu} from "@electron/remote";
import * as t from "../../../common/translation-util";
import * as t from "../../../common/translation-util.js";
export const contextMenu = (
webContents: WebContents,

View File

@@ -1,13 +1,13 @@
import type {Html} from "../../../common/html";
import {html} from "../../../common/html";
import type {Html} from "../../../common/html.js";
import {html} from "../../../common/html.js";
import {generateNodeFromHtml} from "./base";
import type {TabProps} from "./tab";
import Tab from "./tab";
import {generateNodeFromHtml} from "./base.js";
import type {TabProps} from "./tab.js";
import Tab from "./tab.js";
export interface FunctionalTabProps extends TabProps {
export type FunctionalTabProps = {
$view: Element;
}
} & TabProps;
export default class FunctionalTab extends Tab {
$view: Element;

View File

@@ -1,17 +1,17 @@
import process from "node:process";
import type {Html} from "../../../common/html";
import {html} from "../../../common/html";
import {ipcRenderer} from "../typed-ipc-renderer";
import type {Html} from "../../../common/html.js";
import {html} from "../../../common/html.js";
import {ipcRenderer} from "../typed-ipc-renderer.js";
import {generateNodeFromHtml} from "./base";
import type {TabProps} from "./tab";
import Tab from "./tab";
import type WebView from "./webview";
import {generateNodeFromHtml} from "./base.js";
import type {TabProps} from "./tab.js";
import Tab from "./tab.js";
import type WebView from "./webview.js";
export interface ServerTabProps extends TabProps {
export type ServerTabProps = {
webview: Promise<WebView>;
}
} & TabProps;
export default class ServerTab extends Tab {
webview: Promise<WebView>;

View File

@@ -1,6 +1,6 @@
import type {TabRole} from "../../../common/types";
import type {TabRole} from "../../../common/types.js";
export interface TabProps {
export type TabProps = {
role: TabRole;
icon?: string;
name: string;
@@ -12,15 +12,12 @@ export interface TabProps {
onHoverOut?: () => void;
materialIcon?: string;
onDestroy?: () => void;
}
};
export default abstract class Tab {
props: TabProps;
abstract $el: Element;
constructor(props: TabProps) {
this.props = props;
}
constructor(readonly props: TabProps) {}
registerListeners(): void {
this.$el.addEventListener("click", this.props.onClick);

View File

@@ -6,20 +6,20 @@ import process from "node:process";
import * as remote from "@electron/remote";
import {app, dialog} from "@electron/remote";
import * as ConfigUtil from "../../../common/config-util";
import type {Html} from "../../../common/html";
import {html} from "../../../common/html";
import type {RendererMessage} from "../../../common/typed-ipc";
import type {TabRole} from "../../../common/types";
import {ipcRenderer} from "../typed-ipc-renderer";
import * as SystemUtil from "../utils/system-util";
import * as ConfigUtil from "../../../common/config-util.js";
import type {Html} from "../../../common/html.js";
import {html} from "../../../common/html.js";
import type {RendererMessage} from "../../../common/typed-ipc.js";
import type {TabRole} from "../../../common/types.js";
import {ipcRenderer} from "../typed-ipc-renderer.js";
import * as SystemUtil from "../utils/system-util.js";
import {generateNodeFromHtml} from "./base";
import {contextMenu} from "./context-menu";
import {generateNodeFromHtml} from "./base.js";
import {contextMenu} from "./context-menu.js";
const shouldSilentWebview = ConfigUtil.getConfigItem("silent", false);
interface WebViewProps {
type WebViewProps = {
$root: Element;
rootWebContents: WebContents;
index: number;
@@ -32,7 +32,7 @@ interface WebViewProps {
preload?: string;
onTitleChange: () => void;
hasPermission?: (origin: string, permission: string) => boolean;
}
};
export default class WebView {
static templateHtml(props: WebViewProps): Html {
@@ -42,7 +42,7 @@ export default class WebView {
src="${props.url}"
${props.preload === undefined
? html``
: html`preload="${props.preload}"`}
: html`preload="${props.preload}" webpreferences="sandbox=no"`}
partition="persist:webviewsession"
allowpopups
>
@@ -92,7 +92,6 @@ export default class WebView {
return new WebView(props, $element, webContentsId);
}
props: WebViewProps;
zoomFactor: number;
badgeCount: number;
loading: boolean;
@@ -102,11 +101,10 @@ export default class WebView {
webContentsId: number;
private constructor(
props: WebViewProps,
readonly props: WebViewProps,
$element: HTMLElement,
webContentsId: number,
) {
this.props = props;
this.zoomFactor = 1;
this.loading = true;
this.badgeCount = 0;

View File

@@ -1,14 +1,14 @@
import {EventEmitter} from "node:events";
import type {ClipboardDecrypter} from "./clipboard-decrypter";
import {ClipboardDecrypterImpl} from "./clipboard-decrypter";
import type {NotificationData} from "./notification";
import {newNotification} from "./notification";
import {ipcRenderer} from "./typed-ipc-renderer";
import type {ClipboardDecrypter} from "./clipboard-decrypter.js";
import {ClipboardDecrypterImpl} from "./clipboard-decrypter.js";
import type {NotificationData} from "./notification/index.js";
import {newNotification} from "./notification/index.js";
import {ipcRenderer} from "./typed-ipc-renderer.js";
type ListenerType = (...args: any[]) => void;
export interface ElectronBridge {
export type ElectronBridge = {
send_event: (eventName: string | symbol, ...args: unknown[]) => boolean;
on_event: (eventName: string, listener: ListenerType) => void;
new_notification: (
@@ -21,7 +21,7 @@ export interface ElectronBridge {
get_send_notification_reply_message_supported: () => boolean;
set_send_notification_reply_message_supported: (value: boolean) => void;
decrypt_clipboard: (version: number) => ClipboardDecrypter;
}
};
let notificationReplySupported = false;
// Indicates if the user is idle or not

View File

@@ -1,12 +1,12 @@
"use strict";
type ElectronBridge = import("./electron-bridge").ElectronBridge;
type ElectronBridge = import("./electron-bridge.js").ElectronBridge;
interface CompatElectronBridge extends ElectronBridge {
type CompatElectronBridge = {
readonly idle_on_system: boolean;
readonly last_active_on_system: number;
send_notification_reply_message_supported: boolean;
}
} & ElectronBridge;
(() => {
const zulipWindow = window as typeof window & {

View File

@@ -6,25 +6,25 @@ import {Menu, app, dialog, session} from "@electron/remote";
import * as remote from "@electron/remote";
import * as Sentry from "@sentry/electron";
import type {Config} from "../../common/config-util";
import * as ConfigUtil from "../../common/config-util";
import * as DNDUtil from "../../common/dnd-util";
import type {DndSettings} from "../../common/dnd-util";
import * as EnterpriseUtil from "../../common/enterprise-util";
import * as LinkUtil from "../../common/link-util";
import Logger from "../../common/logger-util";
import * as Messages from "../../common/messages";
import type {NavItem, ServerConf, TabData} from "../../common/types";
import type {Config} from "../../common/config-util.js";
import * as ConfigUtil from "../../common/config-util.js";
import * as DNDUtil from "../../common/dnd-util.js";
import type {DndSettings} from "../../common/dnd-util.js";
import * as EnterpriseUtil from "../../common/enterprise-util.js";
import * as LinkUtil from "../../common/link-util.js";
import Logger from "../../common/logger-util.js";
import * as Messages from "../../common/messages.js";
import type {NavItem, ServerConf, TabData} from "../../common/types.js";
import FunctionalTab from "./components/functional-tab";
import ServerTab from "./components/server-tab";
import WebView from "./components/webview";
import {AboutView} from "./pages/about";
import {PreferenceView} from "./pages/preference/preference";
import {initializeTray} from "./tray";
import {ipcRenderer} from "./typed-ipc-renderer";
import * as DomainUtil from "./utils/domain-util";
import ReconnectUtil from "./utils/reconnect-util";
import FunctionalTab from "./components/functional-tab.js";
import ServerTab from "./components/server-tab.js";
import WebView from "./components/webview.js";
import {AboutView} from "./pages/about.js";
import {PreferenceView} from "./pages/preference/preference.js";
import {initializeTray} from "./tray.js";
import {ipcRenderer} from "./typed-ipc-renderer.js";
import * as DomainUtil from "./utils/domain-util.js";
import ReconnectUtil from "./utils/reconnect-util.js";
Sentry.init({});

View File

@@ -1,6 +1,6 @@
import {ipcRenderer} from "../typed-ipc-renderer";
import {ipcRenderer} from "../typed-ipc-renderer.js";
export interface NotificationData {
export type NotificationData = {
close: () => void;
title: string;
dir: NotificationDirection;
@@ -9,7 +9,7 @@ export interface NotificationData {
tag: string;
icon: string;
data: unknown;
}
};
export function newNotification(
title: string,

View File

@@ -1,6 +1,6 @@
import {app} from "@electron/remote";
import {html} from "../../../common/html";
import {html} from "../../../common/html.js";
export class AboutView {
readonly $view: HTMLElement;

View File

@@ -1,4 +1,4 @@
import {ipcRenderer} from "../typed-ipc-renderer";
import {ipcRenderer} from "../typed-ipc-renderer.js";
export function init(
$reconnectButton: Element,

View File

@@ -1,14 +1,14 @@
import type {Html} from "../../../../common/html";
import {html} from "../../../../common/html";
import {generateNodeFromHtml} from "../../components/base";
import {ipcRenderer} from "../../typed-ipc-renderer";
import type {Html} from "../../../../common/html.js";
import {html} from "../../../../common/html.js";
import {generateNodeFromHtml} from "../../components/base.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
interface BaseSectionProps {
type BaseSectionProps = {
$element: HTMLElement;
disabled?: boolean;
value: boolean;
clickHandler: () => void;
}
};
export function generateSettingOption(props: BaseSectionProps): void {
const {$element, disabled, value, clickHandler} = props;

View File

@@ -1,15 +1,15 @@
import {html} from "../../../../common/html";
import * as t from "../../../../common/translation-util";
import {ipcRenderer} from "../../typed-ipc-renderer";
import * as DomainUtil from "../../utils/domain-util";
import {html} from "../../../../common/html.js";
import * as t from "../../../../common/translation-util.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import * as DomainUtil from "../../utils/domain-util.js";
import {reloadApp} from "./base-section";
import {initFindAccounts} from "./find-accounts";
import {initServerInfoForm} from "./server-info-form";
import {reloadApp} from "./base-section.js";
import {initFindAccounts} from "./find-accounts.js";
import {initServerInfoForm} from "./server-info-form.js";
interface ConnectedOrgSectionProps {
type ConnectedOrgSectionProps = {
$root: Element;
}
};
export function initConnectedOrgSection({
$root,

View File

@@ -1,11 +1,11 @@
import {html} from "../../../../common/html";
import * as LinkUtil from "../../../../common/link-util";
import * as t from "../../../../common/translation-util";
import {generateNodeFromHtml} from "../../components/base";
import {html} from "../../../../common/html.js";
import * as LinkUtil from "../../../../common/link-util.js";
import * as t from "../../../../common/translation-util.js";
import {generateNodeFromHtml} from "../../components/base.js";
interface FindAccountsProps {
type FindAccountsProps = {
$root: Element;
}
};
async function findAccounts(url: string): Promise<void> {
if (!url) {

View File

@@ -9,20 +9,20 @@ import Tagify from "@yaireo/tagify";
import ISO6391 from "iso-639-1";
import * as z from "zod";
import * as ConfigUtil from "../../../../common/config-util";
import * as EnterpriseUtil from "../../../../common/enterprise-util";
import {html} from "../../../../common/html";
import * as t from "../../../../common/translation-util";
import * as ConfigUtil from "../../../../common/config-util.js";
import * as EnterpriseUtil from "../../../../common/enterprise-util.js";
import {html} from "../../../../common/html.js";
import * as t from "../../../../common/translation-util.js";
import supportedLocales from "../../../../translations/supported-locales.json";
import {ipcRenderer} from "../../typed-ipc-renderer";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import {generateSelectHtml, generateSettingOption} from "./base-section";
import {generateSelectHtml, generateSettingOption} from "./base-section.js";
const currentBrowserWindow = remote.getCurrentWindow();
interface GeneralSectionProps {
type GeneralSectionProps = {
$root: Element;
}
};
export function initGeneralSection({$root}: GeneralSectionProps): void {
$root.innerHTML = html`
@@ -616,7 +616,7 @@ export function initGeneralSection({$root}: GeneralSectionProps): void {
const availableLanguages = session.fromPartition(
"persist:webviewsession",
).availableSpellCheckerLanguages;
let languagePairs: Map<string, string> = new Map();
let languagePairs = new Map<string, string>();
for (const l of availableLanguages) {
if (ISO6391.validate(l)) {
languagePairs.set(ISO6391.getName(l), l);

View File

@@ -1,20 +1,18 @@
import type {Html} from "../../../../common/html";
import {html} from "../../../../common/html";
import * as t from "../../../../common/translation-util";
import type {NavItem} from "../../../../common/types";
import {generateNodeFromHtml} from "../../components/base";
import type {Html} from "../../../../common/html.js";
import {html} from "../../../../common/html.js";
import * as t from "../../../../common/translation-util.js";
import type {NavItem} from "../../../../common/types.js";
import {generateNodeFromHtml} from "../../components/base.js";
interface PreferenceNavProps {
type PreferenceNavProps = {
$root: Element;
onItemSelected: (navItem: NavItem) => void;
}
};
export default class PreferenceNav {
props: PreferenceNavProps;
navItems: NavItem[];
$el: Element;
constructor(props: PreferenceNavProps) {
this.props = props;
constructor(private readonly props: PreferenceNavProps) {
this.navItems = [
"General",
"Network",

View File

@@ -1,13 +1,13 @@
import * as ConfigUtil from "../../../../common/config-util";
import {html} from "../../../../common/html";
import * as t from "../../../../common/translation-util";
import {ipcRenderer} from "../../typed-ipc-renderer";
import * as ConfigUtil from "../../../../common/config-util.js";
import {html} from "../../../../common/html.js";
import * as t from "../../../../common/translation-util.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import {generateSettingOption} from "./base-section";
import {generateSettingOption} from "./base-section.js";
interface NetworkSectionProps {
type NetworkSectionProps = {
$root: Element;
}
};
export function initNetworkSection({$root}: NetworkSectionProps): void {
$root.innerHTML = html`

View File

@@ -1,16 +1,16 @@
import {dialog} from "@electron/remote";
import {html} from "../../../../common/html";
import * as LinkUtil from "../../../../common/link-util";
import * as t from "../../../../common/translation-util";
import {generateNodeFromHtml} from "../../components/base";
import {ipcRenderer} from "../../typed-ipc-renderer";
import * as DomainUtil from "../../utils/domain-util";
import {html} from "../../../../common/html.js";
import * as LinkUtil from "../../../../common/link-util.js";
import * as t from "../../../../common/translation-util.js";
import {generateNodeFromHtml} from "../../components/base.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import * as DomainUtil from "../../utils/domain-util.js";
interface NewServerFormProps {
type NewServerFormProps = {
$root: Element;
onChange: () => void;
}
};
export function initNewServerForm({$root, onChange}: NewServerFormProps): void {
const $newServerForm = generateNodeFromHtml(html`

View File

@@ -1,16 +1,16 @@
import process from "node:process";
import type {DndSettings} from "../../../../common/dnd-util";
import {html} from "../../../../common/html";
import type {NavItem} from "../../../../common/types";
import {ipcRenderer} from "../../typed-ipc-renderer";
import type {DndSettings} from "../../../../common/dnd-util.js";
import {html} from "../../../../common/html.js";
import type {NavItem} from "../../../../common/types.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import {initConnectedOrgSection} from "./connected-org-section";
import {initGeneralSection} from "./general-section";
import Nav from "./nav";
import {initNetworkSection} from "./network-section";
import {initServersSection} from "./servers-section";
import {initShortcutsSection} from "./shortcuts-section";
import {initConnectedOrgSection} from "./connected-org-section.js";
import {initGeneralSection} from "./general-section.js";
import Nav from "./nav.js";
import {initNetworkSection} from "./network-section.js";
import {initServersSection} from "./servers-section.js";
import {initShortcutsSection} from "./shortcuts-section.js";
export class PreferenceView {
readonly $view: HTMLElement;
@@ -63,29 +63,33 @@ export class PreferenceView {
this.navItem = navItem;
this.nav.select(navItem);
switch (navItem) {
case "AddServer":
case "AddServer": {
initServersSection({
$root: this.$settingsContainer,
});
break;
}
case "General":
case "General": {
initGeneralSection({
$root: this.$settingsContainer,
});
break;
}
case "Organizations":
case "Organizations": {
initConnectedOrgSection({
$root: this.$settingsContainer,
});
break;
}
case "Network":
case "Network": {
initNetworkSection({
$root: this.$settingsContainer,
});
break;
}
case "Shortcuts": {
initShortcutsSection({
@@ -94,8 +98,9 @@ export class PreferenceView {
break;
}
default:
default: {
((n: never) => n)(navItem);
}
}
window.location.hash = `#${navItem}`;

View File

@@ -1,19 +1,19 @@
import {dialog} from "@electron/remote";
import {html} from "../../../../common/html";
import * as Messages from "../../../../common/messages";
import * as t from "../../../../common/translation-util";
import type {ServerConf} from "../../../../common/types";
import {generateNodeFromHtml} from "../../components/base";
import {ipcRenderer} from "../../typed-ipc-renderer";
import * as DomainUtil from "../../utils/domain-util";
import {html} from "../../../../common/html.js";
import * as Messages from "../../../../common/messages.js";
import * as t from "../../../../common/translation-util.js";
import type {ServerConf} from "../../../../common/types.js";
import {generateNodeFromHtml} from "../../components/base.js";
import {ipcRenderer} from "../../typed-ipc-renderer.js";
import * as DomainUtil from "../../utils/domain-util.js";
interface ServerInfoFormProps {
type ServerInfoFormProps = {
$root: Element;
server: ServerConf;
index: number;
onChange: () => void;
}
};
export function initServerInfoForm(props: ServerInfoFormProps): void {
const $serverInfoForm = generateNodeFromHtml(html`

View File

@@ -1,12 +1,12 @@
import {html} from "../../../../common/html";
import * as t from "../../../../common/translation-util";
import {html} from "../../../../common/html.js";
import * as t from "../../../../common/translation-util.js";
import {reloadApp} from "./base-section";
import {initNewServerForm} from "./new-server-form";
import {reloadApp} from "./base-section.js";
import {initNewServerForm} from "./new-server-form.js";
interface ServersSectionProps {
type ServersSectionProps = {
$root: Element;
}
};
export function initServersSection({$root}: ServersSectionProps): void {
$root.innerHTML = html`

View File

@@ -1,12 +1,12 @@
import process from "node:process";
import {html} from "../../../../common/html";
import * as LinkUtil from "../../../../common/link-util";
import * as t from "../../../../common/translation-util";
import {html} from "../../../../common/html.js";
import * as LinkUtil from "../../../../common/link-util.js";
import * as t from "../../../../common/translation-util.js";
interface ShortcutsSectionProps {
type ShortcutsSectionProps = {
$root: Element;
}
};
// eslint-disable-next-line complexity
export function initShortcutsSection({$root}: ShortcutsSectionProps): void {

View File

@@ -1,9 +1,9 @@
import {contextBridge, webFrame} from "electron/renderer";
import fs from "node:fs";
import electron_bridge, {bridgeEvents} from "./electron-bridge";
import * as NetworkError from "./pages/network";
import {ipcRenderer} from "./typed-ipc-renderer";
import electron_bridge, {bridgeEvents} from "./electron-bridge.js";
import * as NetworkError from "./pages/network.js";
import {ipcRenderer} from "./typed-ipc-renderer.js";
contextBridge.exposeInMainWorld("raw_electron_bridge", electron_bridge);

View File

@@ -6,11 +6,11 @@ import process from "node:process";
import {BrowserWindow, Menu, Tray} from "@electron/remote";
import * as ConfigUtil from "../../common/config-util";
import type {RendererMessage} from "../../common/typed-ipc";
import * as ConfigUtil from "../../common/config-util.js";
import type {RendererMessage} from "../../common/typed-ipc.js";
import type {ServerManagerView} from "./main";
import {ipcRenderer} from "./typed-ipc-renderer";
import type {ServerManagerView} from "./main.js";
import {ipcRenderer} from "./typed-ipc-renderer.js";
let tray: ElectronTray | null = null;
@@ -36,14 +36,21 @@ let unread = 0;
const trayIconSize = (): number => {
switch (process.platform) {
case "darwin":
case "darwin": {
return 20;
case "win32":
}
case "win32": {
return 100;
case "linux":
}
case "linux": {
return 100;
default:
}
default: {
return 80;
}
}
};
@@ -236,5 +243,3 @@ export function initializeTray(serverManagerView: ServerManagerView) {
createTray();
}
}
export {};

View File

@@ -7,7 +7,7 @@ import type {
MainCall,
MainMessage,
RendererMessage,
} from "../../common/typed-ipc";
} from "../../common/typed-ipc.js";
type RendererListener<Channel extends keyof RendererMessage> =
RendererMessage[Channel] extends (...args: infer Args) => void

View File

@@ -7,11 +7,11 @@ import {JsonDB} from "node-json-db";
import {DataError} from "node-json-db/dist/lib/Errors";
import * as z from "zod";
import * as EnterpriseUtil from "../../../common/enterprise-util";
import Logger from "../../../common/logger-util";
import * as Messages from "../../../common/messages";
import type {ServerConf} from "../../../common/types";
import {ipcRenderer} from "../typed-ipc-renderer";
import * as EnterpriseUtil from "../../../common/enterprise-util.js";
import Logger from "../../../common/logger-util.js";
import * as Messages from "../../../common/messages.js";
import type {ServerConf} from "../../../common/types.js";
import {ipcRenderer} from "../typed-ipc-renderer.js";
const logger = new Logger({
file: "domain-util.log",

View File

@@ -1,22 +1,20 @@
import * as backoff from "backoff";
import {html} from "../../../common/html";
import Logger from "../../../common/logger-util";
import type WebView from "../components/webview";
import {ipcRenderer} from "../typed-ipc-renderer";
import {html} from "../../../common/html.js";
import Logger from "../../../common/logger-util.js";
import type WebView from "../components/webview.js";
import {ipcRenderer} from "../typed-ipc-renderer.js";
const logger = new Logger({
file: "domain-util.log",
});
export default class ReconnectUtil {
webview: WebView;
url: string;
alreadyReloaded: boolean;
fibonacciBackoff: backoff.Backoff;
constructor(webview: WebView) {
this.webview = webview;
this.url = webview.props.url;
this.alreadyReloaded = false;
this.fibonacciBackoff = backoff.fibonacci({

View File

@@ -1,4 +1,4 @@
import {ipcRenderer} from "../typed-ipc-renderer";
import {ipcRenderer} from "../typed-ipc-renderer.js";
export const connectivityError: string[] = [
"ERR_INTERNET_DISCONNECTED",

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,16 +0,0 @@
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
</dict>
</plist>

View File

@@ -2,6 +2,34 @@
All notable changes to the Zulip desktop app are documented in this file.
### v5.9.4 --2023-01-04
**Fixes**:
- The `com.apple.quarantine` extended attribute is now correctly set for downloaded files on macOS.
- The external link handler ignores invalid URLs.
**Dependencies**:
- Upgraded all dependencies, including Electron 22.0.0.
### v5.9.3 --2022-04-28
**Fixes**:
- Fixed a bug in the automatic updater that would sometimes close the application instead of updating it.
(As with most updater fixes, this fix will take effect when updating _from_ 5.9.3. If you're having trouble updating _to_ 5.9.3, a workaround is to click **Install Later** rather than **Install and Relaunch**, then **Quit** from the menu bar and re-open the application manually.)
**Dependencies**:
- Upgraded all dependencies, including Electron 18.2.0.
### v5.9.2 --2022-04-20
**Dependencies**:
- Upgraded all dependencies, including Electron 18.1.0. This fixes an upstream Electron bug that crashed the application when accessibility tools such as screen readers and grammar assistants are in use.
### v5.9.1 --2022-04-08
**Dependencies**:

View File

@@ -53,20 +53,20 @@
- First download our signing key to make sure the deb you download is correct:
```
sudo apt-key adv --keyserver pool.sks-keyservers.net --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9
```bash
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9
```
- Add the repo to your apt source list :
```
echo "deb https://dl.bintray.com/zulip/debian/ beta main" |
```bash
echo "deb https://download.zulip.com/desktop/apt stable main" |
sudo tee -a /etc/apt/sources.list.d/zulip.list
```
- Now install the client :
```
```bash
sudo apt-get update
sudo apt-get install zulip
```

8114
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "5.9.1",
"version": "5.9.4",
"main": "./app/main",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
@@ -18,7 +18,7 @@
"url": "https://github.com/zulip/zulip-desktop/issues"
},
"engines": {
"node": ">=12.10.0"
"node": ">=16.13.2"
},
"scripts": {
"start": "tsc && electron .",
@@ -69,11 +69,7 @@
}
],
"darkModeSupport": true,
"artifactName": "${productName}-${version}-${arch}.${ext}",
"hardenedRuntime": true,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"gatekeeperAssess": false
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"linux": {
"category": "Chat;GNOME;GTK;Network;InstantMessaging",
@@ -147,17 +143,18 @@
],
"dependencies": {
"@electron/remote": "^2.0.8",
"@sentry/electron": "^3.0.3",
"@sentry/electron": "^4.1.2",
"@yaireo/tagify": "^4.5.0",
"adm-zip": "^0.5.5",
"auto-launch": "^5.0.5",
"backoff": "^2.5.0",
"electron-log": "^4.3.5",
"electron-updater": "^4.6.5",
"electron-updater": "^5.0.1",
"electron-window-state": "^5.0.3",
"escape-goat": "^3.0.0",
"gatemaker": "^1.0.0",
"get-stream": "^6.0.1",
"i18n": "^0.14.1",
"i18n": "^0.15.1",
"iso-639-1": "^2.1.9",
"node-json-db": "^1.3.0",
"semver": "^7.3.5",
@@ -172,22 +169,21 @@
"@types/requestidlecallback": "^0.3.4",
"@types/yaireo__tagify": "^4.3.2",
"dotenv": "^16.0.0",
"electron": "^18.0.1",
"electron": "^22.0.0",
"electron-builder": "^23.0.3",
"electron-notarize": "^1.0.0",
"eslint-import-resolver-typescript": "^2.4.0",
"htmlhint": "^1.1.2",
"medium": "^1.2.0",
"playwright-core": "^1.19.1",
"playwright-core": "^1.30.0-alpha-jan-3-2023",
"pre-commit": "^1.2.2",
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"stylelint": "^14.5.3",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard": "^29.0.0",
"tape": "^5.2.2",
"typescript": "^4.3.5",
"xo": "^0.48.0"
"xo": "^0.53.1"
},
"prettier": {
"bracketSpacing": false,
@@ -199,15 +195,6 @@
"rules": {
"@typescript-eslint/no-dynamic-delete": "off",
"arrow-body-style": "error",
"import/extensions": [
"error",
"always",
{
"pattern": {
"ts": "never"
}
}
],
"import/no-restricted-paths": [
"error",
{
@@ -285,7 +272,8 @@
],
"strict": "error",
"unicorn/prefer-json-parse-buffer": "off",
"unicorn/prefer-module": "off"
"unicorn/prefer-module": "off",
"unicorn/prefer-top-level-await": "off"
},
"envs": [
"node",
@@ -312,9 +300,6 @@
}
],
"unicorn/no-await-expression-member": "off"
},
"settings": {
"import/resolver": "typescript"
}
},
{

View File

@@ -1,10 +1,10 @@
#!/bin/bash
# Link to the binary
ln -sf '/opt/${productFilename}/${executable}' '/usr/bin/${executable}'
ln -sf '/opt/${sanitizedProductName}/${executable}' '/usr/bin/${executable}'
# SUID chrome-sandbox for Electron 5+
chmod 4755 '/opt/${productFilename}/chrome-sandbox' || true
chmod 4755 '/opt/${sanitizedProductName}/chrome-sandbox' || true
update-mime-database /usr/share/mime || true
update-desktop-database /usr/share/applications || true

View File

@@ -1,6 +1,6 @@
"use strict";
const path = require("path");
const process = require("process");
const path = require("node:path");
const process = require("node:process");
const dotenv = require("dotenv");
const {notarize} = require("electron-notarize");

View File

@@ -1,4 +1,5 @@
{
"version": "5.9.3",
"productName": "ZulipTest",
"main": "../app/main/index.js"
}

View File

@@ -1,6 +1,6 @@
"use strict";
const path = require("path");
const process = require("process");
const path = require("node:path");
const process = require("node:process");
const {_electron} = require("playwright-core");
const rimraf = require("rimraf");
@@ -30,19 +30,25 @@ function getAppDataDir() {
let base;
switch (process.platform) {
case "darwin":
case "darwin": {
base = path.join(process.env.HOME, "Library", "Application Support");
break;
case "linux":
base = process.env.XDG_CONFIG_HOME
? process.env.XDG_CONFIG_HOME
: path.join(process.env.HOME, ".config");
}
case "linux": {
base =
process.env.XDG_CONFIG_HOME ?? path.join(process.env.HOME, ".config");
break;
case "win32":
}
case "win32": {
base = process.env.APPDATA;
break;
default:
}
default: {
throw new Error("Could not detect app data dir base.");
}
}
console.log("Detected App Data Dir base:", base);

View File

@@ -16,7 +16,10 @@ test("add-organization", async (t) => {
const mainWindow = await take(windows);
t.equal(await mainWindow.title(), "Zulip");
await mainWindow.fill(".setting-input-value", "chat.zulip.org");
await mainWindow.fill(
".setting-input-value",
"zulip-desktop-test.zulipchat.com",
);
await mainWindow.click("#connect");
const orgWebview = await take(windows);

1
typings.d.ts vendored
View File

@@ -1,4 +1,5 @@
declare namespace Electron {
// https://github.com/electron/typescript-definitions/issues/170
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface IncomingMessage extends NodeJS.ReadableStream {}
}