mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-02 04:53:17 +00:00
Compare commits
23 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 |
@@ -6,10 +6,10 @@ import {JsonDB} from "node-json-db";
|
|||||||
import {DataError} from "node-json-db/dist/lib/Errors";
|
import {DataError} from "node-json-db/dist/lib/Errors";
|
||||||
import type * as z from "zod";
|
import type * as z from "zod";
|
||||||
|
|
||||||
import {configSchemata} from "./config-schemata";
|
import {configSchemata} from "./config-schemata.js";
|
||||||
import * as EnterpriseUtil from "./enterprise-util";
|
import * as EnterpriseUtil from "./enterprise-util.js";
|
||||||
import Logger from "./logger-util";
|
import Logger from "./logger-util.js";
|
||||||
import {app, dialog} from "./remote";
|
import {app, dialog} from "./remote.js";
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
[Key in keyof typeof configSchemata]: z.output<typeof configSchemata[Key]>;
|
[Key in keyof typeof configSchemata]: z.output<typeof configSchemata[Key]>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
import {app} from "./remote";
|
import {app} from "./remote.js";
|
||||||
|
|
||||||
let setupCompleted = false;
|
let setupCompleted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import process from "node:process";
|
|||||||
|
|
||||||
import type * as z from "zod";
|
import type * as z from "zod";
|
||||||
|
|
||||||
import type {dndSettingsSchemata} from "./config-schemata";
|
import type {dndSettingsSchemata} from "./config-schemata.js";
|
||||||
import * as ConfigUtil from "./config-util";
|
import * as ConfigUtil from "./config-util.js";
|
||||||
|
|
||||||
export type DndSettings = {
|
export type DndSettings = {
|
||||||
[Key in keyof typeof dndSettingsSchemata]: z.output<
|
[Key in keyof typeof dndSettingsSchemata]: z.output<
|
||||||
@@ -13,10 +13,10 @@ export type DndSettings = {
|
|||||||
|
|
||||||
type SettingName = keyof DndSettings;
|
type SettingName = keyof DndSettings;
|
||||||
|
|
||||||
interface Toggle {
|
type Toggle = {
|
||||||
dnd: boolean;
|
dnd: boolean;
|
||||||
newSettings: Partial<DndSettings>;
|
newSettings: Partial<DndSettings>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function toggle(): Toggle {
|
export function toggle(): Toggle {
|
||||||
const dnd = !ConfigUtil.getConfigItem("dnd", false);
|
const dnd = !ConfigUtil.getConfigItem("dnd", false);
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import process from "node:process";
|
|||||||
|
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
import {enterpriseConfigSchemata} from "./config-schemata";
|
import {enterpriseConfigSchemata} from "./config-schemata.js";
|
||||||
import Logger from "./logger-util";
|
import Logger from "./logger-util.js";
|
||||||
|
|
||||||
type EnterpriseConfig = {
|
type EnterpriseConfig = {
|
||||||
[Key in keyof typeof enterpriseConfigSchemata]: z.output<
|
[Key in keyof typeof enterpriseConfigSchemata]: z.output<
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import fs from "node:fs";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import {html} from "./html";
|
import {html} from "./html.js";
|
||||||
|
|
||||||
export async function openBrowser(url: URL): Promise<void> {
|
export async function openBrowser(url: URL): Promise<void> {
|
||||||
if (["http:", "https:", "mailto:"].includes(url.protocol)) {
|
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 fs from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
import {initSetUp} from "./default-util";
|
import {initSetUp} from "./default-util.js";
|
||||||
import {app} from "./remote";
|
import {app} from "./remote.js";
|
||||||
|
|
||||||
interface LoggerOptions {
|
type LoggerOptions = {
|
||||||
file?: string;
|
file?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
initSetUp();
|
initSetUp();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
interface DialogBoxError {
|
type DialogBoxError = {
|
||||||
title: string;
|
title: string;
|
||||||
content: string;
|
content: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function invalidZulipServerError(domain: string): string {
|
export function invalidZulipServerError(domain: string): string {
|
||||||
return `${domain} does not appear to be a valid Zulip server. Make sure that
|
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 i18n from "i18n";
|
||||||
|
|
||||||
import * as ConfigUtil from "./config-util";
|
import * as ConfigUtil from "./config-util.js";
|
||||||
|
|
||||||
i18n.configure({
|
i18n.configure({
|
||||||
directory: path.join(__dirname, "../translations/"),
|
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 */
|
/* If no locale present in the json, en is set default */
|
||||||
export function __(phrase: string): string {
|
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 {DndSettings} from "./dnd-util.js";
|
||||||
import type {MenuProps, ServerConf} from "./types";
|
import type {MenuProps, ServerConf} from "./types.js";
|
||||||
|
|
||||||
export interface MainMessage {
|
export type MainMessage = {
|
||||||
"clear-app-settings": () => void;
|
"clear-app-settings": () => void;
|
||||||
"configure-spell-checker": () => void;
|
"configure-spell-checker": () => void;
|
||||||
"fetch-user-agent": () => string;
|
"fetch-user-agent": () => string;
|
||||||
@@ -22,15 +22,15 @@ export interface MainMessage {
|
|||||||
"update-badge": (messageCount: number) => void;
|
"update-badge": (messageCount: number) => void;
|
||||||
"update-menu": (props: MenuProps) => void;
|
"update-menu": (props: MenuProps) => void;
|
||||||
"update-taskbar-icon": (data: string, text: string) => void;
|
"update-taskbar-icon": (data: string, text: string) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface MainCall {
|
export type MainCall = {
|
||||||
"get-server-settings": (domain: string) => ServerConf;
|
"get-server-settings": (domain: string) => ServerConf;
|
||||||
"is-online": (url: string) => boolean;
|
"is-online": (url: string) => boolean;
|
||||||
"save-server-icon": (iconURL: string) => string;
|
"save-server-icon": (iconURL: string) => string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface RendererMessage {
|
export type RendererMessage = {
|
||||||
back: () => void;
|
back: () => void;
|
||||||
"copy-zulip-url": () => void;
|
"copy-zulip-url": () => void;
|
||||||
destroytray: () => void;
|
destroytray: () => void;
|
||||||
@@ -79,4 +79,4 @@ export interface RendererMessage {
|
|||||||
zoomActualSize: () => void;
|
zoomActualSize: () => void;
|
||||||
zoomIn: () => void;
|
zoomIn: () => void;
|
||||||
zoomOut: () => void;
|
zoomOut: () => void;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
export interface MenuProps {
|
export type MenuProps = {
|
||||||
tabs: TabData[];
|
tabs: TabData[];
|
||||||
activeTabIndex?: number;
|
activeTabIndex?: number;
|
||||||
enableMenu?: boolean;
|
enableMenu?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type NavItem =
|
export type NavItem =
|
||||||
| "General"
|
| "General"
|
||||||
@@ -11,16 +11,16 @@ export type NavItem =
|
|||||||
| "Organizations"
|
| "Organizations"
|
||||||
| "Shortcuts";
|
| "Shortcuts";
|
||||||
|
|
||||||
export interface ServerConf {
|
export type ServerConf = {
|
||||||
url: string;
|
url: string;
|
||||||
alias: string;
|
alias: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type TabRole = "server" | "function";
|
export type TabRole = "server" | "function";
|
||||||
|
|
||||||
export interface TabData {
|
export type TabData = {
|
||||||
role: TabRole;
|
role: TabRole;
|
||||||
name: string;
|
name: string;
|
||||||
index: number;
|
index: number;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
import {shell} from "electron/common";
|
import {shell} from "electron/common";
|
||||||
import {app, dialog, session} from "electron/main";
|
import {app, dialog, session} from "electron/main";
|
||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import util from "node:util";
|
|
||||||
|
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import type {UpdateDownloadedEvent, UpdateInfo} from "electron-updater";
|
import type {UpdateDownloadedEvent, UpdateInfo} from "electron-updater";
|
||||||
import {autoUpdater} 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> {
|
export async function appUpdater(updateFromMenu = false): Promise<void> {
|
||||||
// Don't initiate auto-updates in development
|
// Don't initiate auto-updates in development
|
||||||
@@ -37,7 +40,10 @@ export async function appUpdater(updateFromMenu = false): Promise<void> {
|
|||||||
|
|
||||||
autoUpdater.allowPrerelease = isBetaUpdate;
|
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) => {
|
autoUpdater.on("update-available", async (info: UpdateInfo) => {
|
||||||
if (updateFromMenu) {
|
if (updateFromMenu) {
|
||||||
updateAvailable = true;
|
updateAvailable = true;
|
||||||
@@ -104,10 +110,8 @@ Current Version: ${app.getVersion()}`,
|
|||||||
detail: "It will be installed the next time you restart the application",
|
detail: "It will be installed the next time you restart the application",
|
||||||
});
|
});
|
||||||
if (response === 0) {
|
if (response === 0) {
|
||||||
await sleep(1000);
|
quitting = true;
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
// Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app.
|
|
||||||
app.quit();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Init for updates
|
// Init for updates
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import type {BrowserWindow} from "electron/main";
|
|||||||
import {app} from "electron/main";
|
import {app} from "electron/main";
|
||||||
import process from "node:process";
|
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 {
|
function showBadgeCount(messageCount: number, mainWindow: BrowserWindow): void {
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import {Notification, app} from "electron/main";
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import * as ConfigUtil from "../common/config-util";
|
import * as ConfigUtil from "../common/config-util.js";
|
||||||
import * as LinkUtil from "../common/link-util";
|
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 {
|
function isUploadsUrl(server: string, url: URL): boolean {
|
||||||
return url.origin === server && url.pathname.startsWith("/user_uploads/");
|
return url.origin === server && url.pathname.startsWith("/user_uploads/");
|
||||||
@@ -105,7 +105,13 @@ export default function handleExternalLink(
|
|||||||
details: HandlerDetails,
|
details: HandlerDetails,
|
||||||
mainContents: WebContents,
|
mainContents: WebContents,
|
||||||
): void {
|
): void {
|
||||||
const url = new URL(details.url);
|
let url: URL;
|
||||||
|
try {
|
||||||
|
url = new URL(details.url);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const downloadPath = ConfigUtil.getConfigItem(
|
const downloadPath = ConfigUtil.getConfigItem(
|
||||||
"downloadsPath",
|
"downloadsPath",
|
||||||
`${app.getPath("downloads")}`,
|
`${app.getPath("downloads")}`,
|
||||||
|
|||||||
@@ -6,18 +6,20 @@ import process from "node:process";
|
|||||||
import * as remoteMain from "@electron/remote/main";
|
import * as remoteMain from "@electron/remote/main";
|
||||||
import windowStateKeeper from "electron-window-state";
|
import windowStateKeeper from "electron-window-state";
|
||||||
|
|
||||||
import * as ConfigUtil from "../common/config-util";
|
import * as ConfigUtil from "../common/config-util.js";
|
||||||
import type {RendererMessage} from "../common/typed-ipc";
|
import type {RendererMessage} from "../common/typed-ipc.js";
|
||||||
import type {MenuProps} from "../common/types";
|
import type {MenuProps} from "../common/types.js";
|
||||||
|
|
||||||
import {appUpdater} from "./autoupdater";
|
import {appUpdater, shouldQuitForUpdate} from "./autoupdater.js";
|
||||||
import * as BadgeSettings from "./badge-settings";
|
import * as BadgeSettings from "./badge-settings.js";
|
||||||
import handleExternalLink from "./handle-external-link";
|
import handleExternalLink from "./handle-external-link.js";
|
||||||
import * as AppMenu from "./menu";
|
import * as AppMenu from "./menu.js";
|
||||||
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request";
|
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request.js";
|
||||||
import {sentryInit} from "./sentry";
|
import {sentryInit} from "./sentry.js";
|
||||||
import {setAutoLaunch} from "./startup";
|
import {setAutoLaunch} from "./startup.js";
|
||||||
import {ipcMain, send} from "./typed-ipc-main";
|
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
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
const {GDK_BACKEND} = process.env;
|
const {GDK_BACKEND} = process.env;
|
||||||
@@ -73,6 +75,7 @@ function createMainWindow(): BrowserWindow {
|
|||||||
minHeight: 400,
|
minHeight: 400,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: require.resolve("../renderer/js/main"),
|
preload: require.resolve("../renderer/js/main"),
|
||||||
|
sandbox: false,
|
||||||
webviewTag: true,
|
webviewTag: true,
|
||||||
},
|
},
|
||||||
show: false,
|
show: false,
|
||||||
@@ -91,7 +94,7 @@ function createMainWindow(): BrowserWindow {
|
|||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isQuitting) {
|
if (!isQuitting && !shouldQuitForUpdate()) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import path from "node:path";
|
|||||||
import {JsonDB} from "node-json-db";
|
import {JsonDB} from "node-json-db";
|
||||||
import {DataError} from "node-json-db/dist/lib/Errors";
|
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({
|
const logger = new Logger({
|
||||||
file: "linux-update-util.log",
|
file: "linux-update-util.log",
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import getStream from "get-stream";
|
|||||||
import * as semver from "semver";
|
import * as semver from "semver";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
import * as ConfigUtil from "../common/config-util";
|
import * as ConfigUtil from "../common/config-util.js";
|
||||||
import Logger from "../common/logger-util";
|
import Logger from "../common/logger-util.js";
|
||||||
|
|
||||||
import * as LinuxUpdateUtil from "./linux-update-util";
|
import * as LinuxUpdateUtil from "./linux-update-util.js";
|
||||||
import {fetchResponse} from "./request";
|
import {fetchResponse} from "./request.js";
|
||||||
|
|
||||||
const logger = new Logger({
|
const logger = new Logger({
|
||||||
file: "linux-update-util.log",
|
file: "linux-update-util.log",
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import process from "node:process";
|
|||||||
|
|
||||||
import AdmZip from "adm-zip";
|
import AdmZip from "adm-zip";
|
||||||
|
|
||||||
import * as ConfigUtil from "../common/config-util";
|
import * as ConfigUtil from "../common/config-util.js";
|
||||||
import * as DNDUtil from "../common/dnd-util";
|
import * as DNDUtil from "../common/dnd-util.js";
|
||||||
import * as t from "../common/translation-util";
|
import * as t from "../common/translation-util.js";
|
||||||
import type {RendererMessage} from "../common/typed-ipc";
|
import type {RendererMessage} from "../common/typed-ipc.js";
|
||||||
import type {MenuProps, TabData} from "../common/types";
|
import type {MenuProps, TabData} from "../common/types.js";
|
||||||
|
|
||||||
import {appUpdater} from "./autoupdater";
|
import {appUpdater} from "./autoupdater.js";
|
||||||
import {send} from "./typed-ipc-main";
|
import {send} from "./typed-ipc-main.js";
|
||||||
|
|
||||||
const appName = app.name;
|
const appName = app.name;
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import * as Sentry from "@sentry/electron";
|
|||||||
import getStream from "get-stream";
|
import getStream from "get-stream";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
import Logger from "../common/logger-util";
|
import Logger from "../common/logger-util.js";
|
||||||
import * as Messages from "../common/messages";
|
import * as Messages from "../common/messages.js";
|
||||||
import type {ServerConf} from "../common/types";
|
import type {ServerConf} from "../common/types.js";
|
||||||
|
|
||||||
export async function fetchResponse(
|
export async function fetchResponse(
|
||||||
request: ClientRequest,
|
request: ClientRequest,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {app} from "electron/main";
|
|||||||
|
|
||||||
import * as Sentry from "@sentry/electron";
|
import * as Sentry from "@sentry/electron";
|
||||||
|
|
||||||
import {getConfigItem} from "../common/config-util";
|
import {getConfigItem} from "../common/config-util.js";
|
||||||
|
|
||||||
export const sentryInit = (): void => {
|
export const sentryInit = (): void => {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import process from "node:process";
|
|||||||
|
|
||||||
import AutoLaunch from "auto-launch";
|
import AutoLaunch from "auto-launch";
|
||||||
|
|
||||||
import * as ConfigUtil from "../common/config-util";
|
import * as ConfigUtil from "../common/config-util.js";
|
||||||
|
|
||||||
export const setAutoLaunch = async (
|
export const setAutoLaunch = async (
|
||||||
AutoLaunchValue: boolean,
|
AutoLaunchValue: boolean,
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import crypto from "node:crypto";
|
|||||||
// don’t leak anything from the user’s clipboard other than the token
|
// don’t leak anything from the user’s clipboard other than the token
|
||||||
// intended for us.
|
// intended for us.
|
||||||
|
|
||||||
export interface ClipboardDecrypter {
|
export type ClipboardDecrypter = {
|
||||||
version: number;
|
version: number;
|
||||||
key: Uint8Array;
|
key: Uint8Array;
|
||||||
pasted: Promise<string>;
|
pasted: Promise<string>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export class ClipboardDecrypterImpl implements ClipboardDecrypter {
|
export class ClipboardDecrypterImpl implements ClipboardDecrypter {
|
||||||
version: number;
|
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 {
|
export function generateNodeFromHtml(html: Html): Element {
|
||||||
const wrapper = document.createElement("div");
|
const wrapper = document.createElement("div");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import process from "node:process";
|
|||||||
|
|
||||||
import {Menu} from "@electron/remote";
|
import {Menu} from "@electron/remote";
|
||||||
|
|
||||||
import * as t from "../../../common/translation-util";
|
import * as t from "../../../common/translation-util.js";
|
||||||
|
|
||||||
export const contextMenu = (
|
export const contextMenu = (
|
||||||
webContents: WebContents,
|
webContents: WebContents,
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import type {Html} from "../../../common/html";
|
import type {Html} from "../../../common/html.js";
|
||||||
import {html} from "../../../common/html";
|
import {html} from "../../../common/html.js";
|
||||||
|
|
||||||
import {generateNodeFromHtml} from "./base";
|
import {generateNodeFromHtml} from "./base.js";
|
||||||
import type {TabProps} from "./tab";
|
import type {TabProps} from "./tab.js";
|
||||||
import Tab from "./tab";
|
import Tab from "./tab.js";
|
||||||
|
|
||||||
export interface FunctionalTabProps extends TabProps {
|
export type FunctionalTabProps = {
|
||||||
$view: Element;
|
$view: Element;
|
||||||
}
|
} & TabProps;
|
||||||
|
|
||||||
export default class FunctionalTab extends Tab {
|
export default class FunctionalTab extends Tab {
|
||||||
$view: Element;
|
$view: Element;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
import type {Html} from "../../../common/html";
|
import type {Html} from "../../../common/html.js";
|
||||||
import {html} from "../../../common/html";
|
import {html} from "../../../common/html.js";
|
||||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||||
|
|
||||||
import {generateNodeFromHtml} from "./base";
|
import {generateNodeFromHtml} from "./base.js";
|
||||||
import type {TabProps} from "./tab";
|
import type {TabProps} from "./tab.js";
|
||||||
import Tab from "./tab";
|
import Tab from "./tab.js";
|
||||||
import type WebView from "./webview";
|
import type WebView from "./webview.js";
|
||||||
|
|
||||||
export interface ServerTabProps extends TabProps {
|
export type ServerTabProps = {
|
||||||
webview: Promise<WebView>;
|
webview: Promise<WebView>;
|
||||||
}
|
} & TabProps;
|
||||||
|
|
||||||
export default class ServerTab extends Tab {
|
export default class ServerTab extends Tab {
|
||||||
webview: Promise<WebView>;
|
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;
|
role: TabRole;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -12,15 +12,12 @@ export interface TabProps {
|
|||||||
onHoverOut?: () => void;
|
onHoverOut?: () => void;
|
||||||
materialIcon?: string;
|
materialIcon?: string;
|
||||||
onDestroy?: () => void;
|
onDestroy?: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default abstract class Tab {
|
export default abstract class Tab {
|
||||||
props: TabProps;
|
|
||||||
abstract $el: Element;
|
abstract $el: Element;
|
||||||
|
|
||||||
constructor(props: TabProps) {
|
constructor(readonly props: TabProps) {}
|
||||||
this.props = props;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerListeners(): void {
|
registerListeners(): void {
|
||||||
this.$el.addEventListener("click", this.props.onClick);
|
this.$el.addEventListener("click", this.props.onClick);
|
||||||
|
|||||||
@@ -6,20 +6,20 @@ import process from "node:process";
|
|||||||
import * as remote from "@electron/remote";
|
import * as remote from "@electron/remote";
|
||||||
import {app, dialog} from "@electron/remote";
|
import {app, dialog} from "@electron/remote";
|
||||||
|
|
||||||
import * as ConfigUtil from "../../../common/config-util";
|
import * as ConfigUtil from "../../../common/config-util.js";
|
||||||
import type {Html} from "../../../common/html";
|
import type {Html} from "../../../common/html.js";
|
||||||
import {html} from "../../../common/html";
|
import {html} from "../../../common/html.js";
|
||||||
import type {RendererMessage} from "../../../common/typed-ipc";
|
import type {RendererMessage} from "../../../common/typed-ipc.js";
|
||||||
import type {TabRole} from "../../../common/types";
|
import type {TabRole} from "../../../common/types.js";
|
||||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||||
import * as SystemUtil from "../utils/system-util";
|
import * as SystemUtil from "../utils/system-util.js";
|
||||||
|
|
||||||
import {generateNodeFromHtml} from "./base";
|
import {generateNodeFromHtml} from "./base.js";
|
||||||
import {contextMenu} from "./context-menu";
|
import {contextMenu} from "./context-menu.js";
|
||||||
|
|
||||||
const shouldSilentWebview = ConfigUtil.getConfigItem("silent", false);
|
const shouldSilentWebview = ConfigUtil.getConfigItem("silent", false);
|
||||||
|
|
||||||
interface WebViewProps {
|
type WebViewProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
rootWebContents: WebContents;
|
rootWebContents: WebContents;
|
||||||
index: number;
|
index: number;
|
||||||
@@ -32,7 +32,7 @@ interface WebViewProps {
|
|||||||
preload?: string;
|
preload?: string;
|
||||||
onTitleChange: () => void;
|
onTitleChange: () => void;
|
||||||
hasPermission?: (origin: string, permission: string) => boolean;
|
hasPermission?: (origin: string, permission: string) => boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default class WebView {
|
export default class WebView {
|
||||||
static templateHtml(props: WebViewProps): Html {
|
static templateHtml(props: WebViewProps): Html {
|
||||||
@@ -42,7 +42,7 @@ export default class WebView {
|
|||||||
src="${props.url}"
|
src="${props.url}"
|
||||||
${props.preload === undefined
|
${props.preload === undefined
|
||||||
? html``
|
? html``
|
||||||
: html`preload="${props.preload}"`}
|
: html`preload="${props.preload}" webpreferences="sandbox=no"`}
|
||||||
partition="persist:webviewsession"
|
partition="persist:webviewsession"
|
||||||
allowpopups
|
allowpopups
|
||||||
>
|
>
|
||||||
@@ -92,7 +92,6 @@ export default class WebView {
|
|||||||
return new WebView(props, $element, webContentsId);
|
return new WebView(props, $element, webContentsId);
|
||||||
}
|
}
|
||||||
|
|
||||||
props: WebViewProps;
|
|
||||||
zoomFactor: number;
|
zoomFactor: number;
|
||||||
badgeCount: number;
|
badgeCount: number;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -102,11 +101,10 @@ export default class WebView {
|
|||||||
webContentsId: number;
|
webContentsId: number;
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
props: WebViewProps,
|
readonly props: WebViewProps,
|
||||||
$element: HTMLElement,
|
$element: HTMLElement,
|
||||||
webContentsId: number,
|
webContentsId: number,
|
||||||
) {
|
) {
|
||||||
this.props = props;
|
|
||||||
this.zoomFactor = 1;
|
this.zoomFactor = 1;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.badgeCount = 0;
|
this.badgeCount = 0;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import {EventEmitter} from "node:events";
|
import {EventEmitter} from "node:events";
|
||||||
|
|
||||||
import type {ClipboardDecrypter} from "./clipboard-decrypter";
|
import type {ClipboardDecrypter} from "./clipboard-decrypter.js";
|
||||||
import {ClipboardDecrypterImpl} from "./clipboard-decrypter";
|
import {ClipboardDecrypterImpl} from "./clipboard-decrypter.js";
|
||||||
import type {NotificationData} from "./notification";
|
import type {NotificationData} from "./notification/index.js";
|
||||||
import {newNotification} from "./notification";
|
import {newNotification} from "./notification/index.js";
|
||||||
import {ipcRenderer} from "./typed-ipc-renderer";
|
import {ipcRenderer} from "./typed-ipc-renderer.js";
|
||||||
|
|
||||||
type ListenerType = (...args: any[]) => void;
|
type ListenerType = (...args: any[]) => void;
|
||||||
|
|
||||||
export interface ElectronBridge {
|
export type ElectronBridge = {
|
||||||
send_event: (eventName: string | symbol, ...args: unknown[]) => boolean;
|
send_event: (eventName: string | symbol, ...args: unknown[]) => boolean;
|
||||||
on_event: (eventName: string, listener: ListenerType) => void;
|
on_event: (eventName: string, listener: ListenerType) => void;
|
||||||
new_notification: (
|
new_notification: (
|
||||||
@@ -21,7 +21,7 @@ export interface ElectronBridge {
|
|||||||
get_send_notification_reply_message_supported: () => boolean;
|
get_send_notification_reply_message_supported: () => boolean;
|
||||||
set_send_notification_reply_message_supported: (value: boolean) => void;
|
set_send_notification_reply_message_supported: (value: boolean) => void;
|
||||||
decrypt_clipboard: (version: number) => ClipboardDecrypter;
|
decrypt_clipboard: (version: number) => ClipboardDecrypter;
|
||||||
}
|
};
|
||||||
|
|
||||||
let notificationReplySupported = false;
|
let notificationReplySupported = false;
|
||||||
// Indicates if the user is idle or not
|
// Indicates if the user is idle or not
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
"use strict";
|
"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 idle_on_system: boolean;
|
||||||
readonly last_active_on_system: number;
|
readonly last_active_on_system: number;
|
||||||
send_notification_reply_message_supported: boolean;
|
send_notification_reply_message_supported: boolean;
|
||||||
}
|
} & ElectronBridge;
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
const zulipWindow = window as typeof window & {
|
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 remote from "@electron/remote";
|
||||||
import * as Sentry from "@sentry/electron";
|
import * as Sentry from "@sentry/electron";
|
||||||
|
|
||||||
import type {Config} from "../../common/config-util";
|
import type {Config} from "../../common/config-util.js";
|
||||||
import * as ConfigUtil from "../../common/config-util";
|
import * as ConfigUtil from "../../common/config-util.js";
|
||||||
import * as DNDUtil from "../../common/dnd-util";
|
import * as DNDUtil from "../../common/dnd-util.js";
|
||||||
import type {DndSettings} from "../../common/dnd-util";
|
import type {DndSettings} from "../../common/dnd-util.js";
|
||||||
import * as EnterpriseUtil from "../../common/enterprise-util";
|
import * as EnterpriseUtil from "../../common/enterprise-util.js";
|
||||||
import * as LinkUtil from "../../common/link-util";
|
import * as LinkUtil from "../../common/link-util.js";
|
||||||
import Logger from "../../common/logger-util";
|
import Logger from "../../common/logger-util.js";
|
||||||
import * as Messages from "../../common/messages";
|
import * as Messages from "../../common/messages.js";
|
||||||
import type {NavItem, ServerConf, TabData} from "../../common/types";
|
import type {NavItem, ServerConf, TabData} from "../../common/types.js";
|
||||||
|
|
||||||
import FunctionalTab from "./components/functional-tab";
|
import FunctionalTab from "./components/functional-tab.js";
|
||||||
import ServerTab from "./components/server-tab";
|
import ServerTab from "./components/server-tab.js";
|
||||||
import WebView from "./components/webview";
|
import WebView from "./components/webview.js";
|
||||||
import {AboutView} from "./pages/about";
|
import {AboutView} from "./pages/about.js";
|
||||||
import {PreferenceView} from "./pages/preference/preference";
|
import {PreferenceView} from "./pages/preference/preference.js";
|
||||||
import {initializeTray} from "./tray";
|
import {initializeTray} from "./tray.js";
|
||||||
import {ipcRenderer} from "./typed-ipc-renderer";
|
import {ipcRenderer} from "./typed-ipc-renderer.js";
|
||||||
import * as DomainUtil from "./utils/domain-util";
|
import * as DomainUtil from "./utils/domain-util.js";
|
||||||
import ReconnectUtil from "./utils/reconnect-util";
|
import ReconnectUtil from "./utils/reconnect-util.js";
|
||||||
|
|
||||||
Sentry.init({});
|
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;
|
close: () => void;
|
||||||
title: string;
|
title: string;
|
||||||
dir: NotificationDirection;
|
dir: NotificationDirection;
|
||||||
@@ -9,7 +9,7 @@ export interface NotificationData {
|
|||||||
tag: string;
|
tag: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
data: unknown;
|
data: unknown;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function newNotification(
|
export function newNotification(
|
||||||
title: string,
|
title: string,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {app} from "@electron/remote";
|
import {app} from "@electron/remote";
|
||||||
|
|
||||||
import {html} from "../../../common/html";
|
import {html} from "../../../common/html.js";
|
||||||
|
|
||||||
export class AboutView {
|
export class AboutView {
|
||||||
readonly $view: HTMLElement;
|
readonly $view: HTMLElement;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||||
|
|
||||||
export function init(
|
export function init(
|
||||||
$reconnectButton: Element,
|
$reconnectButton: Element,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import type {Html} from "../../../../common/html";
|
import type {Html} from "../../../../common/html.js";
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import {generateNodeFromHtml} from "../../components/base";
|
import {generateNodeFromHtml} from "../../components/base.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
|
|
||||||
interface BaseSectionProps {
|
type BaseSectionProps = {
|
||||||
$element: HTMLElement;
|
$element: HTMLElement;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
value: boolean;
|
value: boolean;
|
||||||
clickHandler: () => void;
|
clickHandler: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function generateSettingOption(props: BaseSectionProps): void {
|
export function generateSettingOption(props: BaseSectionProps): void {
|
||||||
const {$element, disabled, value, clickHandler} = props;
|
const {$element, disabled, value, clickHandler} = props;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
import * as DomainUtil from "../../utils/domain-util";
|
import * as DomainUtil from "../../utils/domain-util.js";
|
||||||
|
|
||||||
import {reloadApp} from "./base-section";
|
import {reloadApp} from "./base-section.js";
|
||||||
import {initFindAccounts} from "./find-accounts";
|
import {initFindAccounts} from "./find-accounts.js";
|
||||||
import {initServerInfoForm} from "./server-info-form";
|
import {initServerInfoForm} from "./server-info-form.js";
|
||||||
|
|
||||||
interface ConnectedOrgSectionProps {
|
type ConnectedOrgSectionProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initConnectedOrgSection({
|
export function initConnectedOrgSection({
|
||||||
$root,
|
$root,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as LinkUtil from "../../../../common/link-util";
|
import * as LinkUtil from "../../../../common/link-util.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import {generateNodeFromHtml} from "../../components/base";
|
import {generateNodeFromHtml} from "../../components/base.js";
|
||||||
|
|
||||||
interface FindAccountsProps {
|
type FindAccountsProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
async function findAccounts(url: string): Promise<void> {
|
async function findAccounts(url: string): Promise<void> {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import Tagify from "@yaireo/tagify";
|
|||||||
import ISO6391 from "iso-639-1";
|
import ISO6391 from "iso-639-1";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
import * as ConfigUtil from "../../../../common/config-util";
|
import * as ConfigUtil from "../../../../common/config-util.js";
|
||||||
import * as EnterpriseUtil from "../../../../common/enterprise-util";
|
import * as EnterpriseUtil from "../../../../common/enterprise-util.js";
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import supportedLocales from "../../../../translations/supported-locales.json";
|
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();
|
const currentBrowserWindow = remote.getCurrentWindow();
|
||||||
|
|
||||||
interface GeneralSectionProps {
|
type GeneralSectionProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initGeneralSection({$root}: GeneralSectionProps): void {
|
export function initGeneralSection({$root}: GeneralSectionProps): void {
|
||||||
$root.innerHTML = html`
|
$root.innerHTML = html`
|
||||||
@@ -616,7 +616,7 @@ export function initGeneralSection({$root}: GeneralSectionProps): void {
|
|||||||
const availableLanguages = session.fromPartition(
|
const availableLanguages = session.fromPartition(
|
||||||
"persist:webviewsession",
|
"persist:webviewsession",
|
||||||
).availableSpellCheckerLanguages;
|
).availableSpellCheckerLanguages;
|
||||||
let languagePairs: Map<string, string> = new Map();
|
let languagePairs = new Map<string, string>();
|
||||||
for (const l of availableLanguages) {
|
for (const l of availableLanguages) {
|
||||||
if (ISO6391.validate(l)) {
|
if (ISO6391.validate(l)) {
|
||||||
languagePairs.set(ISO6391.getName(l), l);
|
languagePairs.set(ISO6391.getName(l), l);
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import type {Html} from "../../../../common/html";
|
import type {Html} from "../../../../common/html.js";
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import type {NavItem} from "../../../../common/types";
|
import type {NavItem} from "../../../../common/types.js";
|
||||||
import {generateNodeFromHtml} from "../../components/base";
|
import {generateNodeFromHtml} from "../../components/base.js";
|
||||||
|
|
||||||
interface PreferenceNavProps {
|
type PreferenceNavProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
onItemSelected: (navItem: NavItem) => void;
|
onItemSelected: (navItem: NavItem) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default class PreferenceNav {
|
export default class PreferenceNav {
|
||||||
props: PreferenceNavProps;
|
|
||||||
navItems: NavItem[];
|
navItems: NavItem[];
|
||||||
$el: Element;
|
$el: Element;
|
||||||
constructor(props: PreferenceNavProps) {
|
constructor(private readonly props: PreferenceNavProps) {
|
||||||
this.props = props;
|
|
||||||
this.navItems = [
|
this.navItems = [
|
||||||
"General",
|
"General",
|
||||||
"Network",
|
"Network",
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import * as ConfigUtil from "../../../../common/config-util";
|
import * as ConfigUtil from "../../../../common/config-util.js";
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
|
|
||||||
import {generateSettingOption} from "./base-section";
|
import {generateSettingOption} from "./base-section.js";
|
||||||
|
|
||||||
interface NetworkSectionProps {
|
type NetworkSectionProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initNetworkSection({$root}: NetworkSectionProps): void {
|
export function initNetworkSection({$root}: NetworkSectionProps): void {
|
||||||
$root.innerHTML = html`
|
$root.innerHTML = html`
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import {dialog} from "@electron/remote";
|
import {dialog} from "@electron/remote";
|
||||||
|
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as LinkUtil from "../../../../common/link-util";
|
import * as LinkUtil from "../../../../common/link-util.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import {generateNodeFromHtml} from "../../components/base";
|
import {generateNodeFromHtml} from "../../components/base.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
import * as DomainUtil from "../../utils/domain-util";
|
import * as DomainUtil from "../../utils/domain-util.js";
|
||||||
|
|
||||||
interface NewServerFormProps {
|
type NewServerFormProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initNewServerForm({$root, onChange}: NewServerFormProps): void {
|
export function initNewServerForm({$root, onChange}: NewServerFormProps): void {
|
||||||
const $newServerForm = generateNodeFromHtml(html`
|
const $newServerForm = generateNodeFromHtml(html`
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
import type {DndSettings} from "../../../../common/dnd-util";
|
import type {DndSettings} from "../../../../common/dnd-util.js";
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import type {NavItem} from "../../../../common/types";
|
import type {NavItem} from "../../../../common/types.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
|
|
||||||
import {initConnectedOrgSection} from "./connected-org-section";
|
import {initConnectedOrgSection} from "./connected-org-section.js";
|
||||||
import {initGeneralSection} from "./general-section";
|
import {initGeneralSection} from "./general-section.js";
|
||||||
import Nav from "./nav";
|
import Nav from "./nav.js";
|
||||||
import {initNetworkSection} from "./network-section";
|
import {initNetworkSection} from "./network-section.js";
|
||||||
import {initServersSection} from "./servers-section";
|
import {initServersSection} from "./servers-section.js";
|
||||||
import {initShortcutsSection} from "./shortcuts-section";
|
import {initShortcutsSection} from "./shortcuts-section.js";
|
||||||
|
|
||||||
export class PreferenceView {
|
export class PreferenceView {
|
||||||
readonly $view: HTMLElement;
|
readonly $view: HTMLElement;
|
||||||
@@ -63,29 +63,33 @@ export class PreferenceView {
|
|||||||
this.navItem = navItem;
|
this.navItem = navItem;
|
||||||
this.nav.select(navItem);
|
this.nav.select(navItem);
|
||||||
switch (navItem) {
|
switch (navItem) {
|
||||||
case "AddServer":
|
case "AddServer": {
|
||||||
initServersSection({
|
initServersSection({
|
||||||
$root: this.$settingsContainer,
|
$root: this.$settingsContainer,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "General":
|
case "General": {
|
||||||
initGeneralSection({
|
initGeneralSection({
|
||||||
$root: this.$settingsContainer,
|
$root: this.$settingsContainer,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "Organizations":
|
case "Organizations": {
|
||||||
initConnectedOrgSection({
|
initConnectedOrgSection({
|
||||||
$root: this.$settingsContainer,
|
$root: this.$settingsContainer,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "Network":
|
case "Network": {
|
||||||
initNetworkSection({
|
initNetworkSection({
|
||||||
$root: this.$settingsContainer,
|
$root: this.$settingsContainer,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "Shortcuts": {
|
case "Shortcuts": {
|
||||||
initShortcutsSection({
|
initShortcutsSection({
|
||||||
@@ -94,8 +98,9 @@ export class PreferenceView {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
((n: never) => n)(navItem);
|
((n: never) => n)(navItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.hash = `#${navItem}`;
|
window.location.hash = `#${navItem}`;
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {dialog} from "@electron/remote";
|
import {dialog} from "@electron/remote";
|
||||||
|
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as Messages from "../../../../common/messages";
|
import * as Messages from "../../../../common/messages.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
import type {ServerConf} from "../../../../common/types";
|
import type {ServerConf} from "../../../../common/types.js";
|
||||||
import {generateNodeFromHtml} from "../../components/base";
|
import {generateNodeFromHtml} from "../../components/base.js";
|
||||||
import {ipcRenderer} from "../../typed-ipc-renderer";
|
import {ipcRenderer} from "../../typed-ipc-renderer.js";
|
||||||
import * as DomainUtil from "../../utils/domain-util";
|
import * as DomainUtil from "../../utils/domain-util.js";
|
||||||
|
|
||||||
interface ServerInfoFormProps {
|
type ServerInfoFormProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
server: ServerConf;
|
server: ServerConf;
|
||||||
index: number;
|
index: number;
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initServerInfoForm(props: ServerInfoFormProps): void {
|
export function initServerInfoForm(props: ServerInfoFormProps): void {
|
||||||
const $serverInfoForm = generateNodeFromHtml(html`
|
const $serverInfoForm = generateNodeFromHtml(html`
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
|
|
||||||
import {reloadApp} from "./base-section";
|
import {reloadApp} from "./base-section.js";
|
||||||
import {initNewServerForm} from "./new-server-form";
|
import {initNewServerForm} from "./new-server-form.js";
|
||||||
|
|
||||||
interface ServersSectionProps {
|
type ServersSectionProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function initServersSection({$root}: ServersSectionProps): void {
|
export function initServersSection({$root}: ServersSectionProps): void {
|
||||||
$root.innerHTML = html`
|
$root.innerHTML = html`
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
|
|
||||||
import {html} from "../../../../common/html";
|
import {html} from "../../../../common/html.js";
|
||||||
import * as LinkUtil from "../../../../common/link-util";
|
import * as LinkUtil from "../../../../common/link-util.js";
|
||||||
import * as t from "../../../../common/translation-util";
|
import * as t from "../../../../common/translation-util.js";
|
||||||
|
|
||||||
interface ShortcutsSectionProps {
|
type ShortcutsSectionProps = {
|
||||||
$root: Element;
|
$root: Element;
|
||||||
}
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line complexity
|
// eslint-disable-next-line complexity
|
||||||
export function initShortcutsSection({$root}: ShortcutsSectionProps): void {
|
export function initShortcutsSection({$root}: ShortcutsSectionProps): void {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {contextBridge, webFrame} from "electron/renderer";
|
import {contextBridge, webFrame} from "electron/renderer";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
import electron_bridge, {bridgeEvents} from "./electron-bridge";
|
import electron_bridge, {bridgeEvents} from "./electron-bridge.js";
|
||||||
import * as NetworkError from "./pages/network";
|
import * as NetworkError from "./pages/network.js";
|
||||||
import {ipcRenderer} from "./typed-ipc-renderer";
|
import {ipcRenderer} from "./typed-ipc-renderer.js";
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("raw_electron_bridge", electron_bridge);
|
contextBridge.exposeInMainWorld("raw_electron_bridge", electron_bridge);
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import process from "node:process";
|
|||||||
|
|
||||||
import {BrowserWindow, Menu, Tray} from "@electron/remote";
|
import {BrowserWindow, Menu, Tray} from "@electron/remote";
|
||||||
|
|
||||||
import * as ConfigUtil from "../../common/config-util";
|
import * as ConfigUtil from "../../common/config-util.js";
|
||||||
import type {RendererMessage} from "../../common/typed-ipc";
|
import type {RendererMessage} from "../../common/typed-ipc.js";
|
||||||
|
|
||||||
import type {ServerManagerView} from "./main";
|
import type {ServerManagerView} from "./main.js";
|
||||||
import {ipcRenderer} from "./typed-ipc-renderer";
|
import {ipcRenderer} from "./typed-ipc-renderer.js";
|
||||||
|
|
||||||
let tray: ElectronTray | null = null;
|
let tray: ElectronTray | null = null;
|
||||||
|
|
||||||
@@ -36,14 +36,21 @@ let unread = 0;
|
|||||||
|
|
||||||
const trayIconSize = (): number => {
|
const trayIconSize = (): number => {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "darwin":
|
case "darwin": {
|
||||||
return 20;
|
return 20;
|
||||||
case "win32":
|
}
|
||||||
|
|
||||||
|
case "win32": {
|
||||||
return 100;
|
return 100;
|
||||||
case "linux":
|
}
|
||||||
|
|
||||||
|
case "linux": {
|
||||||
return 100;
|
return 100;
|
||||||
default:
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
return 80;
|
return 80;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -236,5 +243,3 @@ export function initializeTray(serverManagerView: ServerManagerView) {
|
|||||||
createTray();
|
createTray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type {
|
|||||||
MainCall,
|
MainCall,
|
||||||
MainMessage,
|
MainMessage,
|
||||||
RendererMessage,
|
RendererMessage,
|
||||||
} from "../../common/typed-ipc";
|
} from "../../common/typed-ipc.js";
|
||||||
|
|
||||||
type RendererListener<Channel extends keyof RendererMessage> =
|
type RendererListener<Channel extends keyof RendererMessage> =
|
||||||
RendererMessage[Channel] extends (...args: infer Args) => void
|
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 {DataError} from "node-json-db/dist/lib/Errors";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
import * as EnterpriseUtil from "../../../common/enterprise-util";
|
import * as EnterpriseUtil from "../../../common/enterprise-util.js";
|
||||||
import Logger from "../../../common/logger-util";
|
import Logger from "../../../common/logger-util.js";
|
||||||
import * as Messages from "../../../common/messages";
|
import * as Messages from "../../../common/messages.js";
|
||||||
import type {ServerConf} from "../../../common/types";
|
import type {ServerConf} from "../../../common/types.js";
|
||||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||||
|
|
||||||
const logger = new Logger({
|
const logger = new Logger({
|
||||||
file: "domain-util.log",
|
file: "domain-util.log",
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
import * as backoff from "backoff";
|
import * as backoff from "backoff";
|
||||||
|
|
||||||
import {html} from "../../../common/html";
|
import {html} from "../../../common/html.js";
|
||||||
import Logger from "../../../common/logger-util";
|
import Logger from "../../../common/logger-util.js";
|
||||||
import type WebView from "../components/webview";
|
import type WebView from "../components/webview.js";
|
||||||
import {ipcRenderer} from "../typed-ipc-renderer";
|
import {ipcRenderer} from "../typed-ipc-renderer.js";
|
||||||
|
|
||||||
const logger = new Logger({
|
const logger = new Logger({
|
||||||
file: "domain-util.log",
|
file: "domain-util.log",
|
||||||
});
|
});
|
||||||
|
|
||||||
export default class ReconnectUtil {
|
export default class ReconnectUtil {
|
||||||
webview: WebView;
|
|
||||||
url: string;
|
url: string;
|
||||||
alreadyReloaded: boolean;
|
alreadyReloaded: boolean;
|
||||||
fibonacciBackoff: backoff.Backoff;
|
fibonacciBackoff: backoff.Backoff;
|
||||||
|
|
||||||
constructor(webview: WebView) {
|
constructor(webview: WebView) {
|
||||||
this.webview = webview;
|
|
||||||
this.url = webview.props.url;
|
this.url = webview.props.url;
|
||||||
this.alreadyReloaded = false;
|
this.alreadyReloaded = false;
|
||||||
this.fibonacciBackoff = backoff.fibonacci({
|
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[] = [
|
export const connectivityError: string[] = [
|
||||||
"ERR_INTERNET_DISCONNECTED",
|
"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>
|
|
||||||
22
changelog.md
22
changelog.md
@@ -2,6 +2,28 @@
|
|||||||
|
|
||||||
All notable changes to the Zulip desktop app are documented in this file.
|
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
|
### v5.9.2 --2022-04-20
|
||||||
|
|
||||||
**Dependencies**:
|
**Dependencies**:
|
||||||
|
|||||||
@@ -53,20 +53,20 @@
|
|||||||
|
|
||||||
- First download our signing key to make sure the deb you download is correct:
|
- First download our signing key to make sure the deb you download is correct:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
sudo apt-key adv --keyserver pool.sks-keyservers.net --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9
|
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 69AD12704E71A4803DCA3A682424BE5AE9BD10D9
|
||||||
```
|
```
|
||||||
|
|
||||||
- Add the repo to your apt source list :
|
- Add the repo to your apt source list :
|
||||||
|
|
||||||
```
|
```bash
|
||||||
echo "deb https://dl.bintray.com/zulip/debian/ beta main" |
|
echo "deb https://download.zulip.com/desktop/apt stable main" |
|
||||||
sudo tee -a /etc/apt/sources.list.d/zulip.list
|
sudo tee -a /etc/apt/sources.list.d/zulip.list
|
||||||
```
|
```
|
||||||
|
|
||||||
- Now install the client :
|
- Now install the client :
|
||||||
|
|
||||||
```
|
```bash
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install zulip
|
sudo apt-get install zulip
|
||||||
```
|
```
|
||||||
|
|||||||
7751
package-lock.json
generated
7751
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
39
package.json
39
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"productName": "Zulip",
|
"productName": "Zulip",
|
||||||
"version": "5.9.2",
|
"version": "5.9.4",
|
||||||
"main": "./app/main",
|
"main": "./app/main",
|
||||||
"description": "Zulip Desktop App",
|
"description": "Zulip Desktop App",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"url": "https://github.com/zulip/zulip-desktop/issues"
|
"url": "https://github.com/zulip/zulip-desktop/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.10.0"
|
"node": ">=16.13.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "tsc && electron .",
|
"start": "tsc && electron .",
|
||||||
@@ -69,11 +69,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"darkModeSupport": true,
|
"darkModeSupport": true,
|
||||||
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
"artifactName": "${productName}-${version}-${arch}.${ext}"
|
||||||
"hardenedRuntime": true,
|
|
||||||
"entitlements": "build/entitlements.mac.plist",
|
|
||||||
"entitlementsInherit": "build/entitlements.mac.plist",
|
|
||||||
"gatekeeperAssess": false
|
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"category": "Chat;GNOME;GTK;Network;InstantMessaging",
|
"category": "Chat;GNOME;GTK;Network;InstantMessaging",
|
||||||
@@ -147,7 +143,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.0.8",
|
"@electron/remote": "^2.0.8",
|
||||||
"@sentry/electron": "^3.0.3",
|
"@sentry/electron": "^4.1.2",
|
||||||
"@yaireo/tagify": "^4.5.0",
|
"@yaireo/tagify": "^4.5.0",
|
||||||
"adm-zip": "^0.5.5",
|
"adm-zip": "^0.5.5",
|
||||||
"auto-launch": "^5.0.5",
|
"auto-launch": "^5.0.5",
|
||||||
@@ -156,8 +152,9 @@
|
|||||||
"electron-updater": "^5.0.1",
|
"electron-updater": "^5.0.1",
|
||||||
"electron-window-state": "^5.0.3",
|
"electron-window-state": "^5.0.3",
|
||||||
"escape-goat": "^3.0.0",
|
"escape-goat": "^3.0.0",
|
||||||
|
"gatemaker": "^1.0.0",
|
||||||
"get-stream": "^6.0.1",
|
"get-stream": "^6.0.1",
|
||||||
"i18n": "^0.14.1",
|
"i18n": "^0.15.1",
|
||||||
"iso-639-1": "^2.1.9",
|
"iso-639-1": "^2.1.9",
|
||||||
"node-json-db": "^1.3.0",
|
"node-json-db": "^1.3.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
@@ -172,22 +169,21 @@
|
|||||||
"@types/requestidlecallback": "^0.3.4",
|
"@types/requestidlecallback": "^0.3.4",
|
||||||
"@types/yaireo__tagify": "^4.3.2",
|
"@types/yaireo__tagify": "^4.3.2",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"electron": "^18.0.1",
|
"electron": "^22.0.0",
|
||||||
"electron-builder": "^23.0.3",
|
"electron-builder": "^23.0.3",
|
||||||
"electron-notarize": "^1.0.0",
|
"electron-notarize": "^1.0.0",
|
||||||
"eslint-import-resolver-typescript": "^2.4.0",
|
|
||||||
"htmlhint": "^1.1.2",
|
"htmlhint": "^1.1.2",
|
||||||
"medium": "^1.2.0",
|
"medium": "^1.2.0",
|
||||||
"playwright-core": "^1.19.1",
|
"playwright-core": "^1.30.0-alpha-jan-3-2023",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"stylelint": "^14.5.3",
|
"stylelint": "^14.5.3",
|
||||||
"stylelint-config-prettier": "^9.0.3",
|
"stylelint-config-prettier": "^9.0.3",
|
||||||
"stylelint-config-standard": "^25.0.0",
|
"stylelint-config-standard": "^29.0.0",
|
||||||
"tape": "^5.2.2",
|
"tape": "^5.2.2",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
"xo": "^0.48.0"
|
"xo": "^0.53.1"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"bracketSpacing": false,
|
"bracketSpacing": false,
|
||||||
@@ -199,15 +195,6 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/no-dynamic-delete": "off",
|
"@typescript-eslint/no-dynamic-delete": "off",
|
||||||
"arrow-body-style": "error",
|
"arrow-body-style": "error",
|
||||||
"import/extensions": [
|
|
||||||
"error",
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"pattern": {
|
|
||||||
"ts": "never"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"import/no-restricted-paths": [
|
"import/no-restricted-paths": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
@@ -285,7 +272,8 @@
|
|||||||
],
|
],
|
||||||
"strict": "error",
|
"strict": "error",
|
||||||
"unicorn/prefer-json-parse-buffer": "off",
|
"unicorn/prefer-json-parse-buffer": "off",
|
||||||
"unicorn/prefer-module": "off"
|
"unicorn/prefer-module": "off",
|
||||||
|
"unicorn/prefer-top-level-await": "off"
|
||||||
},
|
},
|
||||||
"envs": [
|
"envs": [
|
||||||
"node",
|
"node",
|
||||||
@@ -312,9 +300,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"unicorn/no-await-expression-member": "off"
|
"unicorn/no-await-expression-member": "off"
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"import/resolver": "typescript"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Link to the binary
|
# 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+
|
# 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-mime-database /usr/share/mime || true
|
||||||
update-desktop-database /usr/share/applications || true
|
update-desktop-database /usr/share/applications || true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const path = require("path");
|
const path = require("node:path");
|
||||||
const process = require("process");
|
const process = require("node:process");
|
||||||
|
|
||||||
const dotenv = require("dotenv");
|
const dotenv = require("dotenv");
|
||||||
const {notarize} = require("electron-notarize");
|
const {notarize} = require("electron-notarize");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"version": "5.9.3",
|
||||||
"productName": "ZulipTest",
|
"productName": "ZulipTest",
|
||||||
"main": "../app/main/index.js"
|
"main": "../app/main/index.js"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const path = require("path");
|
const path = require("node:path");
|
||||||
const process = require("process");
|
const process = require("node:process");
|
||||||
|
|
||||||
const {_electron} = require("playwright-core");
|
const {_electron} = require("playwright-core");
|
||||||
const rimraf = require("rimraf");
|
const rimraf = require("rimraf");
|
||||||
@@ -30,19 +30,25 @@ function getAppDataDir() {
|
|||||||
let base;
|
let base;
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "darwin":
|
case "darwin": {
|
||||||
base = path.join(process.env.HOME, "Library", "Application Support");
|
base = path.join(process.env.HOME, "Library", "Application Support");
|
||||||
break;
|
break;
|
||||||
case "linux":
|
}
|
||||||
base = process.env.XDG_CONFIG_HOME
|
|
||||||
? process.env.XDG_CONFIG_HOME
|
case "linux": {
|
||||||
: path.join(process.env.HOME, ".config");
|
base =
|
||||||
|
process.env.XDG_CONFIG_HOME ?? path.join(process.env.HOME, ".config");
|
||||||
break;
|
break;
|
||||||
case "win32":
|
}
|
||||||
|
|
||||||
|
case "win32": {
|
||||||
base = process.env.APPDATA;
|
base = process.env.APPDATA;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
throw new Error("Could not detect app data dir base.");
|
throw new Error("Could not detect app data dir base.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Detected App Data Dir base:", base);
|
console.log("Detected App Data Dir base:", base);
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ test("add-organization", async (t) => {
|
|||||||
const mainWindow = await take(windows);
|
const mainWindow = await take(windows);
|
||||||
t.equal(await mainWindow.title(), "Zulip");
|
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");
|
await mainWindow.click("#connect");
|
||||||
|
|
||||||
const orgWebview = await take(windows);
|
const orgWebview = await take(windows);
|
||||||
|
|||||||
1
typings.d.ts
vendored
1
typings.d.ts
vendored
@@ -1,4 +1,5 @@
|
|||||||
declare namespace Electron {
|
declare namespace Electron {
|
||||||
// https://github.com/electron/typescript-definitions/issues/170
|
// https://github.com/electron/typescript-definitions/issues/170
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||||
interface IncomingMessage extends NodeJS.ReadableStream {}
|
interface IncomingMessage extends NodeJS.ReadableStream {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user