Compare commits
75 Commits
v1.5.16-rc
...
v1.6.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29df8a8a2e | ||
|
|
429f36ebfc | ||
|
|
5844cb9428 | ||
|
|
3c7de2c08f | ||
|
|
ecc73905c1 | ||
|
|
c0d5a39780 | ||
|
|
d43781df49 | ||
|
|
17b8dbf99a | ||
|
|
58b7bbd3d2 | ||
|
|
95bbe84946 | ||
|
|
afb8403dbb | ||
|
|
e7cb2e4022 | ||
|
|
7600571cf5 | ||
|
|
4e07c64790 | ||
|
|
f4290cd433 | ||
|
|
15922f6656 | ||
|
|
393d701ee9 | ||
|
|
ef5d1f421d | ||
|
|
c71338852e | ||
|
|
033a462015 | ||
|
|
3fd726af5e | ||
|
|
6ca2f4c87d | ||
|
|
0c12630b89 | ||
|
|
d3bc7fb400 | ||
|
|
5333c9ec29 | ||
|
|
09b171c1de | ||
|
|
2cd585cd6c | ||
|
|
0b32f7c87f | ||
|
|
08ef4ff3b1 | ||
|
|
b5e8e5cf75 | ||
|
|
cd19af4003 | ||
|
|
1a4fe2ac3b | ||
|
|
8ed8840b63 | ||
|
|
3cbc9997b9 | ||
|
|
a77ed6e844 | ||
|
|
24dbbfa002 | ||
|
|
4354c508c7 | ||
|
|
36f55c1630 | ||
|
|
e536b07874 | ||
|
|
2346829055 | ||
|
|
1dbbdb252c | ||
|
|
6e15684a04 | ||
|
|
2514a33892 | ||
|
|
302105163d | ||
|
|
c128e75f5d | ||
|
|
99e5271cb8 | ||
|
|
15bb819c8a | ||
|
|
c0b4ab9f67 | ||
|
|
4afd29f62c | ||
|
|
6fdeca93b6 | ||
|
|
c67dcae35e | ||
|
|
942ca3b525 | ||
|
|
83653b3a22 | ||
|
|
e1bdcf2d9e | ||
|
|
8c88e9f0f4 | ||
|
|
0572d62c88 | ||
|
|
121728ba2e | ||
|
|
343d4ea641 | ||
|
|
cc939f9645 | ||
|
|
f6ad5bf54c | ||
|
|
2837c41ca4 | ||
|
|
4954c732ee | ||
|
|
6a5268f09b | ||
|
|
7633009ddb | ||
|
|
e267086a17 | ||
|
|
b3780445d3 | ||
|
|
7113fe7e31 | ||
|
|
719865c033 | ||
|
|
2c5664b76e | ||
|
|
43357fe842 | ||
|
|
6222546e20 | ||
|
|
0b032d7434 | ||
|
|
a1ef707065 | ||
|
|
67cf1e7536 | ||
|
|
8ca9e4ccb1 |
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,3 +1,56 @@
|
||||
Changes in [1.6.0-rc.5](https://github.com/vector-im/riot-web/releases/tag/v1.6.0-rc.5) (2020-04-30)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0-rc.4...v1.6.0-rc.5)
|
||||
|
||||
* Upgrade to React SDK 2.5.0-rc.5 and JS SDK 6.0.0-rc.1
|
||||
* Remove feature flag docs from docs on release
|
||||
[\#13375](https://github.com/vector-im/riot-web/pull/13375)
|
||||
|
||||
Changes in [1.6.0-rc.4](https://github.com/vector-im/riot-web/releases/tag/v1.6.0-rc.4) (2020-04-23)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0-rc.3...v1.6.0-rc.4)
|
||||
|
||||
* Upgrade to React SDK 2.5.0-rc.4 and JS SDK 5.3.1-rc.4
|
||||
|
||||
Changes in [1.6.0-rc.3](https://github.com/vector-im/riot-web/releases/tag/v1.6.0-rc.3) (2020-04-17)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0-rc.2...v1.6.0-rc.3)
|
||||
|
||||
* Upgrade to React SDK 2.5.0-rc.3 and JS SDK 5.3.1-rc.3
|
||||
|
||||
Changes in [1.6.0-rc.2](https://github.com/vector-im/riot-web/releases/tag/v1.6.0-rc.2) (2020-04-16)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.6.0-rc.1...v1.6.0-rc.2)
|
||||
|
||||
* Upgrade to React SDK 2.5.0-rc.2 and JS SDK 5.3.1-rc.2
|
||||
* Enable cross-signing / E2EE by default for DM without config changes
|
||||
|
||||
Changes in [1.6.0-rc.1](https://github.com/vector-im/riot-web/releases/tag/v1.6.0-rc.1) (2020-04-15)
|
||||
====================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.5.16-rc.1...v1.6.0-rc.1)
|
||||
|
||||
* Enable cross-signing / E2EE by default for DM on release
|
||||
[\#13179](https://github.com/vector-im/riot-web/pull/13179)
|
||||
* Upgrade to React SDK 2.5.0-rc.1 and JS SDK 5.3.1-rc.1
|
||||
* Add instruction to resolve the inotify watch limit issue
|
||||
[\#13128](https://github.com/vector-im/riot-web/pull/13128)
|
||||
* docs: labs: add a pointer to config.md
|
||||
[\#13149](https://github.com/vector-im/riot-web/pull/13149)
|
||||
* Fix Electron SSO handling to support multiple profiles
|
||||
[\#13028](https://github.com/vector-im/riot-web/pull/13028)
|
||||
* Add riot-desktop shortcuts for forward/back matching browsers&slack
|
||||
[\#13133](https://github.com/vector-im/riot-web/pull/13133)
|
||||
* Allow rageshake to fail in init
|
||||
[\#13164](https://github.com/vector-im/riot-web/pull/13164)
|
||||
* Fix broken yarn install link in README.md
|
||||
[\#13125](https://github.com/vector-im/riot-web/pull/13125)
|
||||
* fix build:jitsi scripts crash caused by a missing folder
|
||||
[\#13122](https://github.com/vector-im/riot-web/pull/13122)
|
||||
* App load order changes to catch errors better
|
||||
[\#13095](https://github.com/vector-im/riot-web/pull/13095)
|
||||
* Upgrade deps
|
||||
[\#13080](https://github.com/vector-im/riot-web/pull/13080)
|
||||
|
||||
Changes in [1.5.16-rc.1](https://github.com/vector-im/riot-web/releases/tag/v1.5.16-rc.1) (2020-04-08)
|
||||
======================================================================================================
|
||||
[Full Changelog](https://github.com/vector-im/riot-web/compare/v1.5.15...v1.5.16-rc.1)
|
||||
|
||||
20
README.md
20
README.md
@@ -78,7 +78,7 @@ Riot is a modular webapp built with modern ES6 and uses a Node.js build system.
|
||||
Ensure you have the latest LTS version of Node.js installed.
|
||||
|
||||
Using `yarn` instead of `npm` is recommended. Please see the Yarn [install
|
||||
guide](https://yarnpkg.com/docs/install/) if you do not have it already.
|
||||
guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it already.
|
||||
|
||||
1. Install or update `node.js` so that your `node` is at least v10.x.
|
||||
1. Install `yarn` if not present already.
|
||||
@@ -288,6 +288,7 @@ yarn install
|
||||
yarn start
|
||||
```
|
||||
|
||||
|
||||
Wait a few seconds for the initial build to finish; you should see something like:
|
||||
```
|
||||
Hash: b0af76309dd56d7275c8
|
||||
@@ -309,6 +310,23 @@ modifying it. See the [configuration docs](docs/config.md) for details.
|
||||
|
||||
Open http://127.0.0.1:8080/ in your browser to see your newly built Riot.
|
||||
|
||||
**Note**: The build script uses inotify by default on Linux to monitor directories
|
||||
for changes. If the inotify watch limit is too low your build will silently fail.
|
||||
To avoid this issue, we recommend a limit of at least 128M.
|
||||
|
||||
To set a new inotify watch limit, execute:
|
||||
|
||||
```
|
||||
$ sudo sysctl fs.inotify.max_user_watches=131072
|
||||
$ sudo sysctl -p
|
||||
```
|
||||
|
||||
If you wish, you can make this new limit permanent, by executing:
|
||||
|
||||
```
|
||||
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
|
||||
$ sudo sysctl -p
|
||||
```
|
||||
___
|
||||
|
||||
When you make changes to `matrix-react-sdk` or `matrix-js-sdk` they should be
|
||||
|
||||
16
docs/labs.md
16
docs/labs.md
@@ -1,6 +1,7 @@
|
||||
# Labs features
|
||||
|
||||
Some notes on the features you can enable by going to `Settings->Labs`. Not exhaustive, chat in
|
||||
If Labs is enabled in the [Riot config](config.md), you can enable some of these features by going
|
||||
to `Settings->Labs`. This list is non-exhaustive and subject to change, chat in
|
||||
[#riot-web:matrix.org](https://matrix.to/#/#riot-web:matrix.org) for more information.
|
||||
|
||||
**Be warned! Labs features are not finalised, they may be fragile, they may change, they may be
|
||||
@@ -74,14 +75,6 @@ instead of verifying each of their devices.
|
||||
|
||||
This feature is still in development and will be landing in several chunks.
|
||||
|
||||
## Event indexing and E2EE search support using Seshat (`feature_event_indexing`)
|
||||
|
||||
Adds support for search in E2E encrypted rooms. This enables an event indexer
|
||||
that downloads, stores, and indexes room messages for E2E encrypted rooms.
|
||||
|
||||
The existing search will transparently work for encrypted rooms just like it
|
||||
does for non-encrypted.
|
||||
|
||||
## Bridge info tab (`feature_bridge_state`)
|
||||
|
||||
Adds a "Bridge Info" tab to the Room Settings dialog, if a compatible bridge is
|
||||
@@ -94,11 +87,6 @@ tab as the single source of truth just yet.
|
||||
This adds a presence indicator in the room list next to DM rooms where the other
|
||||
person is online.
|
||||
|
||||
## Show padlocks on invite only rooms (`feature_invite_only_padlocks`)
|
||||
|
||||
This adds padlocks to room list tiles and room header for invite only rooms.
|
||||
This feature flag (unlike most) is enabled by default.
|
||||
|
||||
## Custom themes (`feature_custom_themes`)
|
||||
|
||||
Custom themes are possible through Riot's [theme support](./theming.md), though
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "riot-web",
|
||||
"productName": "Riot",
|
||||
"main": "src/electron-main.js",
|
||||
"version": "1.5.16-rc.1",
|
||||
"version": "1.6.0-rc.5",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "New Vector Ltd.",
|
||||
"dependencies": {
|
||||
|
||||
@@ -23,14 +23,8 @@
|
||||
"siteId": 1,
|
||||
"policyUrl": "https://matrix.org/legal/riot-im-cookie-policy"
|
||||
},
|
||||
"phasedRollOut": {
|
||||
"feature_lazyloading": {
|
||||
"offset": 1539684000000,
|
||||
"period": 604800000
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"feature_lazyloading": "enable"
|
||||
"feature_cross_signing": "enable"
|
||||
},
|
||||
"enable_presence_by_hs_url": {
|
||||
"https://matrix.org": false,
|
||||
|
||||
@@ -35,7 +35,7 @@ const tray = require('./tray');
|
||||
const vectorMenu = require('./vectormenu');
|
||||
const webContentsHandler = require('./webcontents-handler');
|
||||
const updater = require('./updater');
|
||||
const protocolInit = require('./protocol');
|
||||
const {getProfileFromDeeplink, protocolInit, recordSSOSession} = require('./protocol');
|
||||
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
const Store = require('electron-store');
|
||||
@@ -68,7 +68,11 @@ if (argv["help"]) {
|
||||
app.exit();
|
||||
}
|
||||
|
||||
if (argv['profile-dir']) {
|
||||
// check if we are passed a profile in the SSO callback url
|
||||
const userDataPathInProtocol = getProfileFromDeeplink(argv["_"]);
|
||||
if (userDataPathInProtocol) {
|
||||
app.setPath('userData', userDataPathInProtocol);
|
||||
} else if (argv['profile-dir']) {
|
||||
app.setPath('userData', argv['profile-dir']);
|
||||
} else if (argv['profile']) {
|
||||
app.setPath('userData', `${app.getPath('userData')}-${argv['profile']}`);
|
||||
@@ -233,6 +237,19 @@ ipcMain.on('ipcCall', async function(ev, payload) {
|
||||
case 'getConfig':
|
||||
ret = vectorConfig;
|
||||
break;
|
||||
case 'navigateBack':
|
||||
if (mainWindow.webContents.canGoBack()) {
|
||||
mainWindow.webContents.goBack();
|
||||
}
|
||||
break;
|
||||
case 'navigateForward':
|
||||
if (mainWindow.webContents.canGoForward()) {
|
||||
mainWindow.webContents.goForward();
|
||||
}
|
||||
break;
|
||||
case 'startSSOFlow':
|
||||
recordSSOSession(args[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
mainWindow.webContents.send('ipcReply', {
|
||||
|
||||
@@ -14,40 +14,91 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const {app} = require('electron');
|
||||
const {app} = require("electron");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
const PROTOCOL = "riot://";
|
||||
const SEARCH_PARAM = "riot-desktop-ssoid";
|
||||
const STORE_FILE_NAME = "sso-sessions.json";
|
||||
|
||||
// we getPath userData before electron-main changes it, so this is the default value
|
||||
const storePath = path.join(app.getPath("userData"), STORE_FILE_NAME);
|
||||
|
||||
const processUrl = (url) => {
|
||||
if (!global.mainWindow) return;
|
||||
console.log("Handling link: ", url);
|
||||
global.mainWindow.loadURL(url.replace("riot://", "vector://"));
|
||||
global.mainWindow.loadURL(url.replace(PROTOCOL, "vector://"));
|
||||
};
|
||||
|
||||
module.exports = () => {
|
||||
// get all args except `hidden` as it'd mean the app would not get focused
|
||||
// XXX: passing args to protocol handlers only works on Windows,
|
||||
// so unpackaged deep-linking and --profile passing won't work on Mac/Linux
|
||||
const args = process.argv.slice(1).filter(arg => arg !== "--hidden" && arg !== "-hidden");
|
||||
if (app.isPackaged) {
|
||||
app.setAsDefaultProtocolClient('riot', process.execPath, args);
|
||||
} else if (process.platform === 'win32') { // on Mac/Linux this would just cause the electron binary to open
|
||||
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
|
||||
app.setAsDefaultProtocolClient('riot', process.execPath, [app.getAppPath(), ...args]);
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
// Protocol handler for macos
|
||||
app.on('open-url', function(ev, url) {
|
||||
ev.preventDefault();
|
||||
processUrl(url);
|
||||
});
|
||||
} else {
|
||||
// Protocol handler for win32/Linux
|
||||
app.on('second-instance', (ev, commandLine) => {
|
||||
const url = commandLine[commandLine.length - 1];
|
||||
if (!url.startsWith("riot://")) return;
|
||||
processUrl(url);
|
||||
});
|
||||
const readStore = () => {
|
||||
try {
|
||||
const s = fs.readFileSync(storePath, { encoding: "utf8" });
|
||||
const o = JSON.parse(s);
|
||||
return typeof o === "object" ? o : {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const writeStore = (data) => {
|
||||
fs.writeFileSync(storePath, JSON.stringify(data));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
recordSSOSession: (sessionID) => {
|
||||
const userDataPath = app.getPath('userData');
|
||||
const store = readStore();
|
||||
for (const key in store) {
|
||||
// ensure each instance only has one (the latest) session ID to prevent the file growing unbounded
|
||||
if (store[key] === userDataPath) {
|
||||
delete store[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
store[sessionID] = userDataPath;
|
||||
writeStore(store);
|
||||
},
|
||||
getProfileFromDeeplink: (args) => {
|
||||
// check if we are passed a profile in the SSO callback url
|
||||
const deeplinkUrl = args.find(arg => arg.startsWith('riot://'));
|
||||
if (deeplinkUrl && deeplinkUrl.includes(SEARCH_PARAM)) {
|
||||
const parsedUrl = new URL(deeplinkUrl);
|
||||
if (parsedUrl.protocol === 'riot:') {
|
||||
const ssoID = parsedUrl.searchParams.get(SEARCH_PARAM);
|
||||
const store = readStore();
|
||||
console.log("Forwarding to profile: ", store[ssoID]);
|
||||
return store[ssoID];
|
||||
}
|
||||
}
|
||||
},
|
||||
protocolInit: () => {
|
||||
// get all args except `hidden` as it'd mean the app would not get focused
|
||||
// XXX: passing args to protocol handlers only works on Windows, so unpackaged deep-linking
|
||||
// --profile/--profile-dir are passed via the SEARCH_PARAM var in the callback url
|
||||
const args = process.argv.slice(1).filter(arg => arg !== "--hidden" && arg !== "-hidden");
|
||||
if (app.isPackaged) {
|
||||
app.setAsDefaultProtocolClient('riot', process.execPath, args);
|
||||
} else if (process.platform === 'win32') { // on Mac/Linux this would just cause the electron binary to open
|
||||
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
|
||||
app.setAsDefaultProtocolClient('riot', process.execPath, [app.getAppPath(), ...args]);
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
// Protocol handler for macos
|
||||
app.on('open-url', function(ev, url) {
|
||||
ev.preventDefault();
|
||||
processUrl(url);
|
||||
});
|
||||
} else {
|
||||
// Protocol handler for win32/Linux
|
||||
app.on('second-instance', (ev, commandLine) => {
|
||||
const url = commandLine[commandLine.length - 1];
|
||||
if (!url.startsWith(PROTOCOL)) return;
|
||||
processUrl(url);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "riot-web",
|
||||
"productName": "Riot",
|
||||
"main": "electron_app/src/electron-main.js",
|
||||
"version": "1.5.16-rc.1",
|
||||
"version": "1.6.0-rc.5",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "New Vector Ltd.",
|
||||
"repository": {
|
||||
@@ -38,7 +38,7 @@
|
||||
"clean": "rimraf lib webapp electron_app/dist",
|
||||
"build": "yarn clean && yarn build:genfiles && yarn build:compile && yarn build:types && yarn build:bundle",
|
||||
"build-stats": "yarn clean && yarn build:genfiles && yarn build:compile && yarn build:types && yarn build:bundle-stats",
|
||||
"build:jitsi": "curl -s https://jitsi.riot.im/libs/external_api.min.js > ./webapp/jitsi_external_api.min.js",
|
||||
"build:jitsi": "scripts/build-jitsi.sh",
|
||||
"build:res": "node scripts/copy-res.js",
|
||||
"build:genfiles": "yarn reskindex && yarn build:res && yarn build:jitsi",
|
||||
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
||||
@@ -68,8 +68,8 @@
|
||||
"favico.js": "^0.3.10",
|
||||
"gfm.css": "^1.1.2",
|
||||
"highlight.js": "^9.13.1",
|
||||
"matrix-js-sdk": "5.3.0-rc.1",
|
||||
"matrix-react-sdk": "2.4.0-rc.1",
|
||||
"matrix-js-sdk": "6.0.0-rc.1",
|
||||
"matrix-react-sdk": "2.5.0-rc.5",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||
"postcss-easings": "^2.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web",
|
||||
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
|
||||
"features": {
|
||||
"feature_cross_signing": "enable"
|
||||
},
|
||||
"piwik": {
|
||||
"url": "https://piwik.riot.im/",
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
"feature_mjolnir": "labs",
|
||||
"feature_dm_verification": "labs",
|
||||
"feature_cross_signing": "enable",
|
||||
"feature_invite_only_padlocks": "enable",
|
||||
"feature_event_indexing": "disable",
|
||||
"feature_bridge_state": "labs",
|
||||
"feature_presence_in_room_list": "labs",
|
||||
"feature_custom_themes": "labs"
|
||||
|
||||
7
scripts/build-jitsi.sh
Executable file
7
scripts/build-jitsi.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ ! -f "./webapp" ]]; then
|
||||
mkdir "./webapp"
|
||||
fi
|
||||
|
||||
curl -s https://jitsi.riot.im/libs/external_api.min.js > ./webapp/jitsi_external_api.min.js
|
||||
7
src/@types/global.d.ts
vendored
7
src/@types/global.d.ts
vendored
@@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {ReactNode} from "react";
|
||||
import "modernizr";
|
||||
import {Renderer} from "react-dom";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -25,7 +25,10 @@ declare global {
|
||||
};
|
||||
|
||||
mxSendRageshake: (text: string, withLogs?: boolean) => void;
|
||||
matrixChat: ReactNode;
|
||||
matrixChat: ReturnType<Renderer>;
|
||||
|
||||
// electron-only
|
||||
ipcRenderer: any;
|
||||
}
|
||||
|
||||
// workaround for https://github.com/microsoft/TypeScript/issues/30933
|
||||
|
||||
46
src/components/structures/ErrorView.tsx
Normal file
46
src/components/structures/ErrorView.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2020 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import * as PropTypes from "prop-types";
|
||||
|
||||
import { _t } from "matrix-react-sdk/src/languageHandler";
|
||||
|
||||
interface IProps {
|
||||
title: string;
|
||||
messages?: string[];
|
||||
}
|
||||
|
||||
const ErrorView: React.FC<IProps> = ({title, messages}) => {
|
||||
return <div className="mx_GenericErrorPage">
|
||||
<div className="mx_GenericErrorPage_box">
|
||||
<h1>{title}</h1>
|
||||
<div>
|
||||
{messages && messages.map(msg => <p key={msg}>
|
||||
{ _t(msg) }
|
||||
</p>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
ErrorView.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
messages: PropTypes.arrayOf(PropTypes.string.isRequired),
|
||||
};
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"Missing indexeddb worker script!": "Missing indexeddb worker script!",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.",
|
||||
"Invalid configuration: no default server specified.": "Invalid configuration: no default server specified.",
|
||||
"Your Riot is misconfigured": "Your Riot is misconfigured",
|
||||
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.": "Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.",
|
||||
"The message from the parser is: %(message)s": "The message from the parser is: %(message)s",
|
||||
"Invalid JSON": "Invalid JSON",
|
||||
"Your Riot is misconfigured": "Your Riot is misconfigured",
|
||||
"Unable to load config file: please refresh the page to try again.": "Unable to load config file: please refresh the page to try again.",
|
||||
"Unexpected error preparing the app. See console for details.": "Unexpected error preparing the app. See console for details.",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.",
|
||||
"Invalid configuration: no default server specified.": "Invalid configuration: no default server specified.",
|
||||
"Open user settings": "Open user settings",
|
||||
"Previous/next recently visited room or community": "Previous/next recently visited room or community",
|
||||
"Riot Desktop on %(platformName)s": "Riot Desktop on %(platformName)s",
|
||||
"Go to your browser to complete Sign In": "Go to your browser to complete Sign In",
|
||||
"Unknown device": "Unknown device",
|
||||
|
||||
@@ -26,7 +26,7 @@ global.React = React;
|
||||
import * as sdk from 'matrix-react-sdk';
|
||||
import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg';
|
||||
import * as VectorConferenceHandler from 'matrix-react-sdk/src/VectorConferenceHandler';
|
||||
import {_t, _td, newTranslatableError} from 'matrix-react-sdk/src/languageHandler';
|
||||
import {_td, newTranslatableError} from 'matrix-react-sdk/src/languageHandler';
|
||||
import AutoDiscoveryUtils from 'matrix-react-sdk/src/utils/AutoDiscoveryUtils';
|
||||
import {AutoDiscovery} from "matrix-js-sdk/src/autodiscovery";
|
||||
import * as Lifecycle from "matrix-react-sdk/src/Lifecycle";
|
||||
@@ -37,10 +37,8 @@ import {parseQs, parseQsFromFragment} from './url_utils';
|
||||
|
||||
import {MatrixClientPeg} from 'matrix-react-sdk/src/MatrixClientPeg';
|
||||
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||
import {setTheme} from "matrix-react-sdk/src/theme";
|
||||
|
||||
import CallHandler from 'matrix-react-sdk/src/CallHandler';
|
||||
import {loadConfig, preparePlatform, loadLanguage, loadOlm} from "./init";
|
||||
|
||||
let lastLocationHashSet = null;
|
||||
|
||||
@@ -128,7 +126,7 @@ function onTokenLoginCompleted() {
|
||||
window.location.href = formatted;
|
||||
}
|
||||
|
||||
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||
export async function loadApp(fragParams: {}) {
|
||||
// XXX: the way we pass the path to the worker script from webpack via html in body's dataset is a hack
|
||||
// but alternatives seem to require changing the interface to passing Workers to js-sdk
|
||||
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
|
||||
@@ -137,99 +135,37 @@ export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||
// the bundling. The js-sdk will just fall back to accessing
|
||||
// indexeddb directly with no worker script, but we want to
|
||||
// make sure the indexeddb script is present, so fail hard.
|
||||
throw new Error("Missing indexeddb worker script!");
|
||||
throw newTranslatableError(_td("Missing indexeddb worker script!"));
|
||||
}
|
||||
MatrixClientPeg.setIndexedDbWorkerScript(vectorIndexeddbWorkerScript);
|
||||
CallHandler.setConferenceHandler(VectorConferenceHandler);
|
||||
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
await loadOlm();
|
||||
|
||||
// set the platform for react sdk
|
||||
preparePlatform();
|
||||
const platform = PlatformPeg.get();
|
||||
|
||||
// Load the config from the platform
|
||||
const configError = await loadConfig();
|
||||
|
||||
// Load language after loading config.json so that settingsDefaults.language can be applied
|
||||
await loadLanguage();
|
||||
|
||||
const params = parseQs(window.location);
|
||||
|
||||
// as quickly as we possibly can, set a default theme...
|
||||
await setTheme();
|
||||
|
||||
// Now that we've loaded the theme (CSS), display the config syntax error if needed.
|
||||
if (configError && configError.err && configError.err instanceof SyntaxError) {
|
||||
const errorMessage = (
|
||||
<div>
|
||||
<p>
|
||||
{_t(
|
||||
"Your Riot configuration contains invalid JSON. Please correct the problem " +
|
||||
"and reload the page.",
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{_t(
|
||||
"The message from the parser is: %(message)s",
|
||||
{message: configError.err.message || _t("Invalid JSON")},
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const GenericErrorPage = sdk.getComponent("structures.GenericErrorPage");
|
||||
return <GenericErrorPage message={errorMessage} title={_t("Your Riot is misconfigured")} />;
|
||||
}
|
||||
|
||||
const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||
console.log("Vector starting at " + urlWithoutQuery);
|
||||
if (configError) {
|
||||
return <div className="error">
|
||||
Unable to load config file: please refresh the page to try again.
|
||||
</div>;
|
||||
} else if (acceptBrowser) {
|
||||
platform.startUpdater();
|
||||
|
||||
try {
|
||||
// Don't bother loading the app until the config is verified
|
||||
const config = await verifyServerConfig();
|
||||
const MatrixChat = sdk.getComponent('structures.MatrixChat');
|
||||
return <MatrixChat
|
||||
onNewScreen={onNewScreen}
|
||||
makeRegistrationUrl={makeRegistrationUrl}
|
||||
ConferenceHandler={VectorConferenceHandler}
|
||||
config={config}
|
||||
realQueryParams={params}
|
||||
startingFragmentQueryParams={fragParams}
|
||||
enableGuest={!config.disable_guests}
|
||||
onTokenLoginCompleted={onTokenLoginCompleted}
|
||||
initialScreenAfterLogin={getScreenFromLocation(window.location)}
|
||||
defaultDeviceDisplayName={platform.getDefaultDeviceDisplayName()}
|
||||
/>;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
platform.startUpdater();
|
||||
|
||||
let errorMessage = err.translatedMessage
|
||||
|| _t("Unexpected error preparing the app. See console for details.");
|
||||
errorMessage = <span>{errorMessage}</span>;
|
||||
|
||||
// Like the compatibility page, AWOOOOOGA at the user
|
||||
const GenericErrorPage = sdk.getComponent("structures.GenericErrorPage");
|
||||
return <GenericErrorPage message={errorMessage} title={_t("Your Riot is misconfigured")} />;
|
||||
}
|
||||
} else {
|
||||
console.error("Browser is missing required features.");
|
||||
// take to a different landing page to AWOOOOOGA at the user
|
||||
const CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
|
||||
return <CompatibilityPage onAccept={function() {
|
||||
if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
|
||||
console.log("User accepts the compatibility risks.");
|
||||
loadApp();
|
||||
}} />;
|
||||
}
|
||||
// Don't bother loading the app until the config is verified
|
||||
const config = await verifyServerConfig();
|
||||
const MatrixChat = sdk.getComponent('structures.MatrixChat');
|
||||
return <MatrixChat
|
||||
onNewScreen={onNewScreen}
|
||||
makeRegistrationUrl={makeRegistrationUrl}
|
||||
ConferenceHandler={VectorConferenceHandler}
|
||||
config={config}
|
||||
realQueryParams={params}
|
||||
startingFragmentQueryParams={fragParams}
|
||||
enableGuest={!config.disable_guests}
|
||||
onTokenLoginCompleted={onTokenLoginCompleted}
|
||||
initialScreenAfterLogin={getScreenFromLocation(window.location)}
|
||||
defaultDeviceDisplayName={platform.getDefaultDeviceDisplayName()}
|
||||
/>;
|
||||
}
|
||||
|
||||
async function verifyServerConfig() {
|
||||
|
||||
@@ -33,11 +33,13 @@ if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('sw.js');
|
||||
}
|
||||
|
||||
async function settled(prom: Promise<any>) {
|
||||
try {
|
||||
await prom;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
async function settled(...promises: Array<Promise<any>>) {
|
||||
for (const prom of promises) {
|
||||
try {
|
||||
await prom;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,47 +78,130 @@ function checkBrowserFeatures() {
|
||||
return featureComplete;
|
||||
}
|
||||
|
||||
let acceptBrowser = checkBrowserFeatures();
|
||||
if (!acceptBrowser && window.localStorage) {
|
||||
acceptBrowser = Boolean(window.localStorage.getItem("mx_accepts_unsupported_browser"));
|
||||
}
|
||||
|
||||
// React depends on Map & Set which we check for using modernizr's es6collections
|
||||
// if modernizr fails we may not have a functional react to show the error message.
|
||||
// try in react but fallback to an `alert`
|
||||
// We start loading stuff but don't block on it until as late as possible to allow
|
||||
// the browser to use as much parallelism as it can.
|
||||
// Load parallelism is based on research in https://github.com/vector-im/riot-web/issues/12253
|
||||
async function start() {
|
||||
// load init.ts async so that its code is not executed immediately and we can catch any exceptions
|
||||
const {rageshakePromise, loadSkin, loadApp} = await import(
|
||||
const {
|
||||
rageshakePromise,
|
||||
preparePlatform,
|
||||
loadOlm,
|
||||
loadConfig,
|
||||
loadSkin,
|
||||
loadLanguage,
|
||||
loadTheme,
|
||||
loadApp,
|
||||
showError,
|
||||
showIncompatibleBrowser,
|
||||
_t,
|
||||
} = await import(
|
||||
/* webpackChunkName: "init" */
|
||||
/* webpackPreload: true */
|
||||
"./init");
|
||||
|
||||
await settled(rageshakePromise); // give rageshake a chance to load/fail
|
||||
try {
|
||||
// give rageshake a chance to load/fail, we don't actually assert rageshake loads, we allow it to fail if no IDB
|
||||
await settled(rageshakePromise);
|
||||
|
||||
const fragparts = parseQsFromFragment(window.location);
|
||||
const fragparts = parseQsFromFragment(window.location);
|
||||
|
||||
// don't try to redirect to the native apps if we're
|
||||
// verifying a 3pid (but after we've loaded the config)
|
||||
// or if the user is following a deep link
|
||||
// (https://github.com/vector-im/riot-web/issues/7378)
|
||||
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
|
||||
// don't try to redirect to the native apps if we're
|
||||
// verifying a 3pid (but after we've loaded the config)
|
||||
// or if the user is following a deep link
|
||||
// (https://github.com/vector-im/riot-web/issues/7378)
|
||||
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
|
||||
|
||||
if (!preventRedirect) {
|
||||
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
||||
const isAndroid = /Android/.test(navigator.userAgent);
|
||||
if (isIos || isAndroid) {
|
||||
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
|
||||
window.location.href = "mobile_guide/";
|
||||
return;
|
||||
if (!preventRedirect) {
|
||||
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
||||
const isAndroid = /Android/.test(navigator.userAgent);
|
||||
if (isIos || isAndroid) {
|
||||
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
|
||||
window.location.href = "mobile_guide/";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loadOlmPromise = loadOlm();
|
||||
// set the platform for react sdk
|
||||
preparePlatform();
|
||||
// load config requires the platform to be ready
|
||||
const loadConfigPromise = loadConfig();
|
||||
await settled(loadConfigPromise); // wait for it to settle
|
||||
// keep initialising so that we can show any possible error with as many features (theme, i18n) as possible
|
||||
|
||||
// Load language after loading config.json so that settingsDefaults.language can be applied
|
||||
const loadLanguagePromise = loadLanguage();
|
||||
// as quickly as we possibly can, set a default theme...
|
||||
const loadThemePromise = loadTheme();
|
||||
const loadSkinPromise = loadSkin();
|
||||
|
||||
// await things settling so that any errors we have to render have features like i18n running
|
||||
await settled(loadSkinPromise, loadThemePromise, loadLanguagePromise);
|
||||
|
||||
// ##########################
|
||||
// error handling begins here
|
||||
// ##########################
|
||||
if (!acceptBrowser) {
|
||||
await new Promise(resolve => {
|
||||
console.error("Browser is missing required features.");
|
||||
// take to a different landing page to AWOOOOOGA at the user
|
||||
showIncompatibleBrowser(() => {
|
||||
if (window.localStorage) {
|
||||
window.localStorage.setItem('mx_accepts_unsupported_browser', String(true));
|
||||
}
|
||||
console.log("User accepts the compatibility risks.");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// await config here
|
||||
await loadConfigPromise;
|
||||
} catch (error) {
|
||||
// Now that we've loaded the theme (CSS), display the config syntax error if needed.
|
||||
if (error.err && error.err instanceof SyntaxError) {
|
||||
return showError(_t("Your Riot is misconfigured"), [
|
||||
_t("Your Riot configuration contains invalid JSON. Please correct the problem and reload the page."),
|
||||
_t("The message from the parser is: %(message)s", { message: error.err.message || _t("Invalid JSON")}),
|
||||
]);
|
||||
}
|
||||
return showError(_t("Unable to load config file: please refresh the page to try again."));
|
||||
}
|
||||
|
||||
// ##################################
|
||||
// app load critical path starts here
|
||||
// assert things started successfully
|
||||
// ##################################
|
||||
await loadOlmPromise;
|
||||
await loadSkinPromise;
|
||||
await loadThemePromise;
|
||||
await loadLanguagePromise;
|
||||
|
||||
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
|
||||
// run on the components.
|
||||
await loadApp(fragparts.params);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// Like the compatibility page, AWOOOOOGA at the user
|
||||
await showError(_t("Your Riot is misconfigured"), [
|
||||
err.translatedMessage || _t("Unexpected error preparing the app. See console for details."),
|
||||
]);
|
||||
}
|
||||
|
||||
await loadSkin();
|
||||
|
||||
let acceptBrowser = checkBrowserFeatures();
|
||||
if (!acceptBrowser && window.localStorage) {
|
||||
acceptBrowser = Boolean(window.localStorage.getItem("mx_accepts_unsupported_browser"));
|
||||
}
|
||||
|
||||
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
|
||||
// run on the components. We use `require` here to make sure webpack doesn't optimize this into an async
|
||||
// import and thus running before the skin can load.
|
||||
await loadApp(fragparts.params, acceptBrowser);
|
||||
}
|
||||
start();
|
||||
start().catch(err => {
|
||||
console.error(err);
|
||||
if (!acceptBrowser) {
|
||||
// TODO redirect to static incompatible browser page
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
import olmWasmPath from "olm/olm.wasm";
|
||||
import Olm from 'olm';
|
||||
import * as ReactDOM from "react-dom";
|
||||
import * as React from "react";
|
||||
|
||||
import * as languageHandler from "matrix-react-sdk/src/languageHandler";
|
||||
import SettingsStore from "matrix-react-sdk/src/settings/SettingsStore";
|
||||
@@ -28,6 +29,7 @@ import ElectronPlatform from "./platform/ElectronPlatform";
|
||||
import WebPlatform from "./platform/WebPlatform";
|
||||
import PlatformPeg from "matrix-react-sdk/src/PlatformPeg";
|
||||
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||
import {setTheme} from "matrix-react-sdk/src/theme";
|
||||
|
||||
import { initRageshake } from "./rageshakesetup";
|
||||
|
||||
@@ -35,7 +37,7 @@ import { initRageshake } from "./rageshakesetup";
|
||||
export const rageshakePromise = initRageshake();
|
||||
|
||||
export function preparePlatform() {
|
||||
if ((<any>window).ipcRenderer) {
|
||||
if (window.ipcRenderer) {
|
||||
console.log("Using Electron platform");
|
||||
const plaf = new ElectronPlatform();
|
||||
PlatformPeg.set(plaf);
|
||||
@@ -45,21 +47,12 @@ export function preparePlatform() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadConfig(): Promise<Error | void> {
|
||||
const platform = PlatformPeg.get();
|
||||
|
||||
let configJson;
|
||||
try {
|
||||
configJson = await platform.getConfig();
|
||||
} catch (e) {
|
||||
return e;
|
||||
} finally {
|
||||
// XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure
|
||||
// granular settings are loaded correctly and to avoid duplicating the override logic for the theme.
|
||||
//
|
||||
// Note: this isn't called twice for some wrappers, like the Jitsi wrapper.
|
||||
SdkConfig.put(configJson || {});
|
||||
}
|
||||
export async function loadConfig() {
|
||||
// XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure
|
||||
// granular settings are loaded correctly and to avoid duplicating the override logic for the theme.
|
||||
//
|
||||
// Note: this isn't called twice for some wrappers, like the Jitsi wrapper.
|
||||
SdkConfig.put(await PlatformPeg.get().getConfig() || {});
|
||||
}
|
||||
|
||||
export function loadOlm(): Promise<void> {
|
||||
@@ -138,12 +131,36 @@ export async function loadSkin() {
|
||||
console.log("Skin loaded!");
|
||||
}
|
||||
|
||||
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||
export async function loadTheme() {
|
||||
setTheme();
|
||||
}
|
||||
|
||||
export async function loadApp(fragParams: {}) {
|
||||
// load app.js async so that its code is not executed immediately and we can catch any exceptions
|
||||
const module = await import(
|
||||
/* webpackChunkName: "riot-web-app" */
|
||||
/* webpackPreload: true */
|
||||
"./app");
|
||||
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser),
|
||||
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams),
|
||||
document.getElementById('matrixchat'));
|
||||
}
|
||||
|
||||
export async function showError(title: string, messages?: string[]) {
|
||||
const ErrorView = (await import(
|
||||
/* webpackChunkName: "error-view" */
|
||||
/* webpackPreload: true */
|
||||
"../components/structures/ErrorView")).default;
|
||||
window.matrixChat = ReactDOM.render(<ErrorView title={title} messages={messages} />,
|
||||
document.getElementById('matrixchat'));
|
||||
}
|
||||
|
||||
export async function showIncompatibleBrowser(onAccept) {
|
||||
const CompatibilityPage = (await import(
|
||||
/* webpackChunkName: "compatibility-page" */
|
||||
/* webpackPreload: true */
|
||||
"matrix-react-sdk/src/components/structures/CompatibilityPage")).default;
|
||||
window.matrixChat = ReactDOM.render(<CompatibilityPage onAccept={onAccept} />,
|
||||
document.getElementById('matrixchat'));
|
||||
}
|
||||
|
||||
export const _t = languageHandler._t;
|
||||
@@ -32,6 +32,7 @@ import Spinner from "matrix-react-sdk/src/components/views/elements/Spinner";
|
||||
import {Categories, Modifiers, registerShortcut} from "matrix-react-sdk/src/accessibility/KeyboardShortcuts";
|
||||
import {Key} from "matrix-react-sdk/src/Keyboard";
|
||||
import React from "react";
|
||||
import {randomString} from "matrix-js-sdk/src/randomstring";
|
||||
|
||||
const ipcRenderer = window.ipcRenderer;
|
||||
const isMac = navigator.platform.toUpperCase().includes('MAC');
|
||||
@@ -218,7 +219,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
||||
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
|
||||
|
||||
// register Mac specific shortcuts
|
||||
// register OS-specific shortcuts
|
||||
if (isMac) {
|
||||
registerShortcut(Categories.NAVIGATION, {
|
||||
keybinds: [{
|
||||
@@ -227,7 +228,33 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}],
|
||||
description: _td("Open user settings"),
|
||||
});
|
||||
|
||||
registerShortcut(Categories.NAVIGATION, {
|
||||
keybinds: [{
|
||||
modifiers: [Modifiers.COMMAND],
|
||||
key: Key.SQUARE_BRACKET_LEFT,
|
||||
}, {
|
||||
modifiers: [Modifiers.COMMAND],
|
||||
key: Key.SQUARE_BRACKET_RIGHT,
|
||||
}],
|
||||
description: _td("Previous/next recently visited room or community"),
|
||||
});
|
||||
} else {
|
||||
registerShortcut(Categories.NAVIGATION, {
|
||||
keybinds: [{
|
||||
modifiers: [Modifiers.ALT],
|
||||
key: Key.ARROW_LEFT,
|
||||
}, {
|
||||
modifiers: [Modifiers.ALT],
|
||||
key: Key.ARROW_RIGHT,
|
||||
}],
|
||||
description: _td("Previous/next recently visited room or community"),
|
||||
});
|
||||
}
|
||||
|
||||
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
|
||||
this.ssoID = randomString(32);
|
||||
this._ipcCall("startSSOFlow", this.ssoID);
|
||||
}
|
||||
|
||||
async getConfig(): Promise<{}> {
|
||||
@@ -424,6 +451,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
getSSOCallbackUrl(hsUrl: string, isUrl: string): URL {
|
||||
const url = super.getSSOCallbackUrl(hsUrl, isUrl);
|
||||
url.protocol = "riot";
|
||||
url.searchParams.set("riot-desktop-ssoid", this.ssoID);
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -434,4 +462,32 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
description: <Spinner />,
|
||||
});
|
||||
}
|
||||
|
||||
_navigateForwardBack(back: boolean) {
|
||||
this._ipcCall(back ? "navigateBack" : "navigateForward");
|
||||
}
|
||||
|
||||
onKeyDown(ev: KeyboardEvent): boolean {
|
||||
let handled = false;
|
||||
|
||||
switch (ev.key) {
|
||||
case Key.SQUARE_BRACKET_LEFT:
|
||||
case Key.SQUARE_BRACKET_RIGHT:
|
||||
if (isMac && ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey) {
|
||||
this._navigateForwardBack(ev.key === Key.SQUARE_BRACKET_LEFT);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Key.ARROW_LEFT:
|
||||
case Key.ARROW_RIGHT:
|
||||
if (!isMac && ev.altKey && !ev.metaKey && !ev.ctrlKey && !ev.shiftKey) {
|
||||
this._navigateForwardBack(ev.key === Key.ARROW_LEFT);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user