mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-10-24 08:33:36 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56ab0833b8 | ||
|
|
c62b393c52 | ||
|
|
991de77cad | ||
|
|
94780c44c8 | ||
|
|
82542a6390 | ||
|
|
53ff8443dc | ||
|
|
3855ecab58 | ||
|
|
a57cbb4aa8 | ||
|
|
56a4461c2a | ||
|
|
cd023ec5ab | ||
|
|
1aa4ade3c0 | ||
|
|
dcb46eef4f | ||
|
|
e3e8ef6e3e | ||
|
|
6808b1971a | ||
|
|
1dd5269549 | ||
|
|
d33adca1e8 | ||
|
|
8ea7f7864f | ||
|
|
493ae06e52 | ||
|
|
2b8f3536d3 | ||
|
|
544d23ec09 | ||
|
|
588d32fd22 | ||
|
|
1c471fe624 | ||
|
|
52486d687d | ||
|
|
73441d791c | ||
|
|
1bb6423721 |
@@ -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]>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
|
||||
import {app} from "./remote";
|
||||
import {app} from "./remote.js";
|
||||
|
||||
let setupCompleted = false;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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")}`,
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -16,11 +16,11 @@ import crypto from "node:crypto";
|
||||
// don’t leak anything from the user’s 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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 & {
|
||||
|
||||
@@ -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({});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
||||
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||
|
||||
export function init(
|
||||
$reconnectButton: Element,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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}`;
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
||||
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||
|
||||
export const connectivityError: string[] = [
|
||||
"ERR_INTERNET_DISCONNECTED",
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
28
changelog.md
28
changelog.md
@@ -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**:
|
||||
|
||||
@@ -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
8114
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@@ -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"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"version": "5.9.3",
|
||||
"productName": "ZulipTest",
|
||||
"main": "../app/main/index.js"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
1
typings.d.ts
vendored
@@ -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 {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user