mirror of https://github.com/vector-im/riot-web
extract config error handling out of app.js
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/13095/head
parent
6a5268f09b
commit
4954c732ee
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
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";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
title: React.ReactNode;
|
||||||
|
message: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ErrorView: React.FC<IProps> = ({title, message}) => {
|
||||||
|
return <div className="mx_GenericErrorPage">
|
||||||
|
<div className="mx_GenericErrorPage_box">
|
||||||
|
<h1>{ title }</h1>
|
||||||
|
<p>{ message }</p>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorView.propTypes = {
|
||||||
|
title: PropTypes.object.isRequired, // jsx for title
|
||||||
|
message: PropTypes.object.isRequired, // jsx to display
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorView;
|
||||||
|
|
|
@ -126,7 +126,7 @@ function onTokenLoginCompleted() {
|
||||||
window.location.href = formatted;
|
window.location.href = formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadApp(fragParams: {}, acceptBrowser: boolean, configError: Error|void) {
|
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||||
// XXX: the way we pass the path to the worker script from webpack via html in body's dataset is a hack
|
// 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
|
// but alternatives seem to require changing the interface to passing Workers to js-sdk
|
||||||
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
|
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
|
||||||
|
@ -146,36 +146,9 @@ export async function loadApp(fragParams: {}, acceptBrowser: boolean, configErro
|
||||||
|
|
||||||
const params = parseQs(window.location);
|
const params = parseQs(window.location);
|
||||||
|
|
||||||
// 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;
|
const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname;
|
||||||
console.log("Vector starting at " + urlWithoutQuery);
|
console.log("Vector starting at " + urlWithoutQuery);
|
||||||
if (configError) {
|
if (acceptBrowser) {
|
||||||
return <div className="error">
|
|
||||||
Unable to load config file: please refresh the page to try again.
|
|
||||||
</div>;
|
|
||||||
} else if (acceptBrowser) {
|
|
||||||
platform.startUpdater();
|
platform.startUpdater();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -97,6 +97,8 @@ async function start() {
|
||||||
loadLanguage,
|
loadLanguage,
|
||||||
loadTheme,
|
loadTheme,
|
||||||
loadApp,
|
loadApp,
|
||||||
|
showError,
|
||||||
|
_t,
|
||||||
} = await import(
|
} = await import(
|
||||||
/* webpackChunkName: "init" */
|
/* webpackChunkName: "init" */
|
||||||
/* webpackPreload: true */
|
/* webpackPreload: true */
|
||||||
|
@ -130,12 +132,18 @@ async function start() {
|
||||||
// load config requires the platform to be ready
|
// load config requires the platform to be ready
|
||||||
const loadConfigPromise = loadConfig();
|
const loadConfigPromise = loadConfig();
|
||||||
|
|
||||||
let configError;
|
|
||||||
try {
|
try {
|
||||||
// await config here
|
// await config here
|
||||||
await loadConfigPromise;
|
await loadConfigPromise;
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
configError = err;
|
// 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."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load language after loading config.json so that settingsDefaults.language can be applied
|
// Load language after loading config.json so that settingsDefaults.language can be applied
|
||||||
|
@ -150,9 +158,27 @@ async function start() {
|
||||||
await loadThemePromise;
|
await loadThemePromise;
|
||||||
await loadLanguagePromise;
|
await loadLanguagePromise;
|
||||||
|
|
||||||
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
|
if (!acceptBrowser) {
|
||||||
// run on the components.
|
await new Promise(resolve => {
|
||||||
await loadApp(fragparts.params, acceptBrowser, configError);
|
// todo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, acceptBrowser);
|
||||||
|
} catch (err) {
|
||||||
|
console.trace(err);
|
||||||
|
// check errors in this order:
|
||||||
|
// Browser Compatibility (skippable)
|
||||||
|
// config.json
|
||||||
|
// runtime errors
|
||||||
|
const { showError } = await import(
|
||||||
|
/* webpackChunkName: "init" */
|
||||||
|
/* webpackPreload: true */
|
||||||
|
"./init");
|
||||||
|
await showError(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start().catch(err => {
|
start().catch(err => {
|
||||||
if (!acceptBrowser) {
|
if (!acceptBrowser) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ limitations under the License.
|
||||||
import olmWasmPath from "olm/olm.wasm";
|
import olmWasmPath from "olm/olm.wasm";
|
||||||
import Olm from 'olm';
|
import Olm from 'olm';
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
import * as languageHandler from "matrix-react-sdk/src/languageHandler";
|
import * as languageHandler from "matrix-react-sdk/src/languageHandler";
|
||||||
import SettingsStore from "matrix-react-sdk/src/settings/SettingsStore";
|
import SettingsStore from "matrix-react-sdk/src/settings/SettingsStore";
|
||||||
|
@ -134,12 +135,31 @@ export async function loadTheme() {
|
||||||
setTheme();
|
setTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadApp(fragParams: {}, acceptBrowser: boolean, configError: Error|void) {
|
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
|
||||||
// load app.js async so that its code is not executed immediately and we can catch any exceptions
|
// load app.js async so that its code is not executed immediately and we can catch any exceptions
|
||||||
const module = await import(
|
const module = await import(
|
||||||
/* webpackChunkName: "riot-web-app" */
|
/* webpackChunkName: "riot-web-app" */
|
||||||
/* webpackPreload: true */
|
/* webpackPreload: true */
|
||||||
"./app");
|
"./app");
|
||||||
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser, configError),
|
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser),
|
||||||
document.getElementById('matrixchat'));
|
document.getElementById('matrixchat'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showError(title: string, messages?: string[]) {
|
||||||
|
const ErrorView = (await import(
|
||||||
|
/* webpackChunkName: "error-view" */
|
||||||
|
/* webpackPreload: true */
|
||||||
|
"../components/structures/ErrorView")).default;
|
||||||
|
const message = <div>
|
||||||
|
{messages && messages.map(msg => <p key={msg}>
|
||||||
|
{languageHandler._t(
|
||||||
|
"Your Riot configuration contains invalid JSON. Please correct the problem and reload the page.",
|
||||||
|
)}
|
||||||
|
</p>)}
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
window.matrixChat = ReactDOM.render(<ErrorView title={title} message={message} />,
|
||||||
|
document.getElementById('matrixchat'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const _t = languageHandler._t;
|
||||||
|
|
Loading…
Reference in New Issue