Compare commits

...

11 Commits

Author SHA1 Message Date
Michael Telatynski
95b600e49d Merge branch 'develop' of github.com:vector-im/element-desktop into t3chguy/types
# Conflicts:
#	yarn.lock
2022-12-01 06:32:27 +00:00
Michael Telatynski
6d065ed16c Simplify @types/node devDep 2022-12-01 06:29:49 +00:00
renovate[bot]
017721ecca Update dependency fs-extra to v10 (#473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-01 04:46:39 +00:00
renovate[bot]
5d0f3921b4 Update dependency eslint-plugin-unicorn to v45 (#470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-01 04:01:46 +00:00
renovate[bot]
ee28079c2b Update jest monorepo to v29 (#466)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-30 16:49:11 +00:00
Michael Telatynski
031ee44571 Enable noImplicitAny and kill off request (#457)
* Enable noImplicitAny

* Switch from request to node-fetch

* Fix node-fetch via patch-package

* Add edge to handler

* Pin node-fetch to v2
2022-11-30 13:51:54 +00:00
Michael Telatynski
c74fdb632b Update generate-packages-index.ts 2022-11-30 11:26:57 +00:00
Michael Telatynski
d72bf8b414 Update generate-packages-index.ts 2022-11-30 11:23:21 +00:00
Michael Telatynski
34e96ea25e Update CODEOWNERS (#464) 2022-11-29 23:27:48 +00:00
ElementRobot
18f61ab734 Merge pull request #463 from vector-im/actions/upgrade-deps
Upgrade dependencies
2022-11-29 20:56:03 +00:00
t3chguy
705972d87b [create-pull-request] automated change 2022-11-29 16:20:02 +00:00
15 changed files with 1206 additions and 1185 deletions

5
.github/CODEOWNERS vendored
View File

@@ -1 +1,4 @@
* @vector-im/element-web
* @vector-im/element-web
/.github/workflows/** @vector-im/element-web-app-team
/package.json @vector-im/element-web-app-team
/yarn.lock @vector-im/element-web-app-team

View File

@@ -46,8 +46,8 @@
"electron-store": "^8.0.2",
"electron-window-state": "^5.0.3",
"minimist": "^1.2.6",
"png-to-ico": "^2.1.1",
"request": "^2.88.2"
"node-fetch": "^2",
"png-to-ico": "^2.1.1"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.213.0",
@@ -58,9 +58,10 @@
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/detect-libc": "^1.0.0",
"@types/jest": "^28",
"@types/jest": "^29.0.0",
"@types/minimist": "^1.2.1",
"@types/mkdirp": "^1.0.2",
"@types/node": "^16",
"@types/pacote": "^11.1.1",
"@types/rimraf": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^5.42.0",
@@ -68,7 +69,7 @@
"allchange": "^1.0.6",
"app-builder-lib": "^22.14.10",
"asar": "^2.0.1",
"babel-jest": "^28.1.3",
"babel-jest": "^29.0.0",
"chokidar": "^3.5.2",
"detect-libc": "^1.0.3",
"electron": "^21",
@@ -79,12 +80,12 @@
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^0.7.0",
"eslint-plugin-unicorn": "^44.0.2",
"eslint-plugin-unicorn": "^45.0.0",
"expect-playwright": "^0.8.0",
"find-npm-prefix": "^1.0.2",
"fs-extra": "^8.1.0",
"fs-extra": "^10.0.0",
"glob": "^7.1.6",
"jest": "^28",
"jest": "^29.0.0",
"matrix-web-i18n": "^1.3.0",
"mkdirp": "^1.0.3",
"needle": "^2.5.0",
@@ -93,7 +94,7 @@
"playwright": "^1.25.0",
"rimraf": "^3.0.2",
"tar": "^6.1.2",
"ts-jest": "^28.0.8",
"ts-jest": "^29.0.0",
"ts-node": "^10.9.1",
"typescript": "4.5.5"
},
@@ -101,9 +102,6 @@
"matrix-seshat": "^2.3.3",
"keytar": "^7.9.0"
},
"resolutions": {
"@types/node": "16.11.38"
},
"build": {
"appId": "im.riot.app",
"asarUnpack": "**/*.node",

View File

@@ -101,7 +101,7 @@ function humanFileSize(bytes: number, si = false, dp = 1) {
return bytes.toFixed(dp) + ' ' + units[u];
}
const dateTimeOptions = {
const dateTimeOptions: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "2-digit",

View File

@@ -20,27 +20,26 @@ import AutoLaunch from "auto-launch";
import { AppLocalization } from "../language-helper";
// global type extensions need to use var for whatever reason
/* eslint-disable no-var */
declare global {
namespace NodeJS {
interface Global {
mainWindow: BrowserWindow;
appQuitting: boolean;
appLocalization: AppLocalization;
launcher: AutoLaunch;
vectorConfig: Record<string, any>;
trayConfig: {
// eslint-disable-next-line camelcase
icon_path: string;
brand: string;
};
store: Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
disableHardwareAcceleration?: boolean;
}>;
}
}
var mainWindow: BrowserWindow | null;
var appQuitting: boolean;
var appLocalization: AppLocalization;
var launcher: AutoLaunch;
var vectorConfig: Record<string, any>;
var trayConfig: {
// eslint-disable-next-line camelcase
icon_path: string;
brand: string;
};
var store: Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
disableHardwareAcceleration?: boolean;
}>;
}
/* eslint-enable no-var */

View File

@@ -126,6 +126,8 @@ async function tryPaths(name: string, root: string, rawPaths: string[]): Promise
throw new Error(`Failed to find ${name} files`);
}
const homeserverProps = ['default_is_url', 'default_hs_url', 'default_server_name', 'default_server_config'] as const;
// Find the webapp resources and set up things that require them
async function setupGlobals(): Promise<void> {
// find the webapp asar.
@@ -168,12 +170,14 @@ async function setupGlobals(): Promise<void> {
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
// defined, and panics as a result.
const homeserverProps = ['default_is_url', 'default_hs_url', 'default_server_name', 'default_server_config'];
if (Object.keys(localConfig).find(k => homeserverProps.includes(k))) {
if (Object.keys(localConfig).find(k => homeserverProps.includes(<any>k))) {
// Rip out all the homeserver options from the vector config
global.vectorConfig = Object.keys(global.vectorConfig)
.filter(k => !homeserverProps.includes(k))
.reduce((obj, key) => {obj[key] = global.vectorConfig[key]; return obj;}, {});
.filter(k => !homeserverProps.includes(<any>k))
.reduce((obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
}, {} as Omit<Partial<typeof global["vectorConfig"]>, keyof typeof homeserverProps>);
}
global.vectorConfig = Object.assign(global.vectorConfig, localConfig);
@@ -244,7 +248,7 @@ const warnBeforeExit = (event: Event, input: Input): void => {
const exitShortcutPressed =
input.type === 'keyDown' && exitShortcuts.some(shortcutFn => shortcutFn(input, process.platform));
if (shouldWarnBeforeExit && exitShortcutPressed) {
if (shouldWarnBeforeExit && exitShortcutPressed && global.mainWindow) {
const shouldCancelCloseRequest = dialog.showMessageBoxSync(global.mainWindow, {
type: "question",
buttons: [_t("Cancel"), _t("Close %(brand)s", {
@@ -338,11 +342,11 @@ app.on('ready', async () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { default: installExt, REACT_DEVELOPER_TOOLS, REACT_PERF } = require('electron-devtools-installer');
installExt(REACT_DEVELOPER_TOOLS)
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log('An error occurred: ', err));
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log('An error occurred: ', err));
installExt(REACT_PERF)
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log('An error occurred: ', err));
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log('An error occurred: ', err));
} catch (e) {
console.log(e);
}
@@ -446,6 +450,7 @@ app.on('ready', async () => {
if (global.store.get('minimizeToTray', true)) tray.create(global.trayConfig);
global.mainWindow.once('ready-to-show', () => {
if (!global.mainWindow) return;
mainWindowState.manage(global.mainWindow);
if (!argv['hidden']) {
@@ -469,12 +474,12 @@ app.on('ready', async () => {
// behave, eg. Mail.app)
e.preventDefault();
if (global.mainWindow.isFullScreen()) {
global.mainWindow.once('leave-full-screen', () => global.mainWindow.hide());
if (global.mainWindow?.isFullScreen()) {
global.mainWindow.once('leave-full-screen', () => global.mainWindow?.hide());
global.mainWindow.setFullScreen(false);
} else {
global.mainWindow.hide();
global.mainWindow?.hide();
}
return false;
@@ -484,9 +489,9 @@ app.on('ready', async () => {
if (process.platform === 'win32') {
// Handle forward/backward mouse buttons in Windows
global.mainWindow.on('app-command', (e, cmd) => {
if (cmd === 'browser-backward' && global.mainWindow.webContents.canGoBack()) {
if (cmd === 'browser-backward' && global.mainWindow?.webContents.canGoBack()) {
global.mainWindow.webContents.goBack();
} else if (cmd === 'browser-forward' && global.mainWindow.webContents.canGoForward()) {
} else if (cmd === 'browser-forward' && global.mainWindow?.webContents.canGoForward()) {
global.mainWindow.webContents.goForward();
}
});
@@ -508,7 +513,7 @@ app.on('window-all-closed', () => {
});
app.on('activate', () => {
global.mainWindow.show();
global.mainWindow?.show();
});
function beforeQuit(): void {

View File

@@ -39,7 +39,7 @@ ipcMain.on('loudNotification', function(): void {
if (process.platform === 'win32' && global.mainWindow && !global.mainWindow.isFocused() && !focusHandlerAttached) {
global.mainWindow.flashFrame(true);
global.mainWindow.once('focus', () => {
global.mainWindow.flashFrame(false);
global.mainWindow?.flashFrame(false);
focusHandlerAttached = false;
});
focusHandlerAttached = true;

View File

@@ -63,7 +63,7 @@ export function _t(text: string, variables: IVariables = {}): string {
type Component = () => void;
type TypedStore = Store<{ locale?: string[] }>;
type TypedStore = Store<{ locale?: string | string[] }>;
export class AppLocalization {
private static readonly STORE_KEY = "locale";

View File

@@ -52,7 +52,7 @@ function processUrl(url: string): void {
global.mainWindow.loadURL(urlToLoad.href);
}
function readStore(): object {
function readStore(): Record<string, string> {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
@@ -62,7 +62,7 @@ function readStore(): object {
}
}
function writeStore(data: object): void {
function writeStore(data: Record<string, string>): void {
fs.writeFileSync(storePath, JSON.stringify(data));
}
@@ -83,7 +83,7 @@ export function recordSSOSession(sessionID: string): void {
export function getProfileFromDeeplink(args: string[]): string | undefined {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find(arg => arg.startsWith(PROTOCOL + '//'));
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
if (deeplinkUrl?.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === PROTOCOL) {
const ssoID = parsedUrl.searchParams.get(SEARCH_PARAM)!;

View File

@@ -81,15 +81,12 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
// We do this here to ensure we get the path after --profile has been resolved
const eventStorePath = path.join(app.getPath('userData'), 'EventStore');
const sendError = (id, e) => {
const sendError = (id: string, e: Error) => {
const error = {
message: e.message,
};
global.mainWindow.webContents.send('seshatReply', {
id: id,
error: error,
});
global.mainWindow?.webContents.send('seshatReply', { id, error });
};
const args = payload.args || [];
@@ -138,7 +135,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
eventIndex = new Seshat(eventStorePath, { passphrase });
} else {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -153,7 +150,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
await index.shutdown();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -182,7 +179,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
eventIndex?.addEvent(args[0], args[1]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -191,7 +188,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.deleteEvent(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -200,7 +197,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.commit();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -209,7 +206,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex?.search(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
break;
@@ -221,7 +218,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
ret = await eventIndex.addHistoricEvents(
args[0], args[1], args[2]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -233,7 +230,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.getStats();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -245,7 +242,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.removeCrawlerCheckpoint(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -257,7 +254,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.addCrawlerCheckpoint(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -269,7 +266,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.loadFileEvents(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -292,7 +289,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
await eventIndex.setUserVersion(args[0]);
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}
@@ -304,7 +301,7 @@ ipcMain.on('seshat', async function(_ev: IpcMainEvent, payload): Promise<void> {
try {
ret = await eventIndex.getUserVersion();
} catch (e) {
sendError(payload.id, e);
sendError(payload.id, <Error>e);
return;
}
}

View File

@@ -44,12 +44,12 @@ export const Settings: Record<string, Setting> = {
},
"Electron.alwaysShowMenuBar": { // not supported on macOS
async read(): Promise<any> {
return !global.mainWindow.autoHideMenuBar;
return !global.mainWindow!.autoHideMenuBar;
},
async write(value: any): Promise<void> {
global.store.set('autoHideMenuBar', !value);
global.mainWindow.autoHideMenuBar = !value;
global.mainWindow.setMenuBarVisibility(value);
global.mainWindow!.autoHideMenuBar = !value;
global.mainWindow!.setMenuBarVisibility(value);
},
},
"Electron.showTrayIcon": { // not supported on macOS

View File

@@ -36,12 +36,12 @@ export function destroy(): void {
}
function toggleWin(): void {
if (global.mainWindow.isVisible() && !global.mainWindow.isMinimized() && global.mainWindow.isFocused()) {
if (global.mainWindow?.isVisible() && !global.mainWindow.isMinimized() && global.mainWindow.isFocused()) {
global.mainWindow.hide();
} else {
if (global.mainWindow.isMinimized()) global.mainWindow.restore();
if (!global.mainWindow.isVisible()) global.mainWindow.show();
global.mainWindow.focus();
if (global.mainWindow?.isMinimized()) global.mainWindow.restore();
if (!global.mainWindow?.isVisible()) global.mainWindow?.show();
global.mainWindow?.focus();
}
}
@@ -60,11 +60,11 @@ export function create(config: IConfig): void {
initApplicationMenu();
trayIcon.on('click', toggleWin);
let lastFavicon = null;
global.mainWindow.webContents.on('page-favicon-updated', async function(ev, favicons) {
let lastFavicon: string | null = null;
global.mainWindow?.webContents.on('page-favicon-updated', async function(ev, favicons) {
if (!favicons || favicons.length <= 0 || !favicons[0].startsWith('data:')) {
if (lastFavicon !== null) {
global.mainWindow.setIcon(defaultIcon);
global.mainWindow?.setIcon(defaultIcon);
trayIcon?.setImage(defaultIcon);
lastFavicon = null;
}
@@ -89,10 +89,10 @@ export function create(config: IConfig): void {
}
trayIcon?.setImage(newFavicon);
global.mainWindow.setIcon(newFavicon);
global.mainWindow?.setIcon(newFavicon);
});
global.mainWindow.webContents.on('page-title-updated', function(ev, title) {
global.mainWindow?.webContents.on('page-title-updated', function(ev, title) {
trayIcon?.setToolTip(title);
});
}

View File

@@ -98,7 +98,7 @@ export function buildMenuTemplate(): Menu {
// in macOS the Preferences menu item goes in the first menu
...(!isMac ? [{
label: _t('Preferences'),
click() { global.mainWindow.webContents.send('preferences'); },
click() { global.mainWindow?.webContents.send('preferences'); },
}] : []),
{
role: 'togglefullscreen',
@@ -153,7 +153,7 @@ export function buildMenuTemplate(): Menu {
{
label: _t('Preferences') + '…',
accelerator: 'Command+,', // Mac-only accelerator
click() { global.mainWindow.webContents.send('preferences'); },
click() { global.mainWindow?.webContents.send('preferences'); },
},
{ type: 'separator' },
{

View File

@@ -31,7 +31,8 @@ import {
} from 'electron';
import url from 'url';
import fs from 'fs';
import request from 'request';
import fetch from 'node-fetch';
import { pipeline } from 'stream';
import path from 'path';
import { _t } from './language-helper';
@@ -154,7 +155,10 @@ function onLinkContextMenu(ev: Event, params: ContextMenuParams, webContents: We
if (url.startsWith("data:")) {
await writeNativeImage(filePath, nativeImage.createFromDataURL(url));
} else {
request.get(url).pipe(fs.createWriteStream(filePath));
const resp = await fetch(url);
if (!resp.ok) throw new Error(`unexpected response ${resp.statusText}`);
if (!resp.body) throw new Error(`unexpected response has no body ${resp.statusText}`);
pipeline(resp.body, fs.createWriteStream(filePath));
}
} catch (err) {
console.error(err);
@@ -224,7 +228,7 @@ function cutCopyPasteSelectContextMenus(params: ContextMenuParams): MenuItemCons
return options;
}
function onSelectedContextMenu(ev, params) {
function onSelectedContextMenu(ev: Event, params: ContextMenuParams) {
const items = cutCopyPasteSelectContextMenus(params);
const popupMenu = Menu.buildFromTemplate(items);

View File

@@ -5,7 +5,6 @@
"module": "commonjs",
"moduleResolution": "node",
"target": "es2016",
"noImplicitAny": false,
"sourceMap": false,
"outDir": "./lib",
"rootDir": "./src",

2204
yarn.lock
View File

File diff suppressed because it is too large Load Diff