extract config error handling out of app.js

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-04-08 19:47:52 +01:00
parent 6a5268f09b
commit 4954c732ee
4 changed files with 96 additions and 37 deletions

View file

@ -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;

View file

@ -126,7 +126,7 @@ function onTokenLoginCompleted() {
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
// but alternatives seem to require changing the interface to passing Workers to js-sdk
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
@ -146,36 +146,9 @@ export async function loadApp(fragParams: {}, acceptBrowser: boolean, configErro
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;
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) {
if (acceptBrowser) {
platform.startUpdater();
try {

View file

@ -97,6 +97,8 @@ async function start() {
loadLanguage,
loadTheme,
loadApp,
showError,
_t,
} = await import(
/* webpackChunkName: "init" */
/* webpackPreload: true */
@ -130,12 +132,18 @@ async function start() {
// load config requires the platform to be ready
const loadConfigPromise = loadConfig();
let configError;
try {
// await config here
await loadConfigPromise;
} catch (err) {
configError = err;
} 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."));
}
// Load language after loading config.json so that settingsDefaults.language can be applied
@ -150,9 +158,27 @@ async function start() {
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, acceptBrowser, configError);
if (!acceptBrowser) {
await new Promise(resolve => {
// 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 => {
if (!acceptBrowser) {

View file

@ -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";
@ -134,12 +135,31 @@ export async function loadTheme() {
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
const module = await import(
/* webpackChunkName: "riot-web-app" */
/* webpackPreload: true */
"./app");
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser, configError),
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser),
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;