Commit 504b8314 authored by Robert Knight's avatar Robert Knight

Display visual error when config fetch fails

Display a visual error message if fetching the client's configuration fails,
eg. due to a failure to fetch a grant token in the LMS app.
parent 265fed83
import Panel from './Panel';
/**
* @typedef LaunchErrorPanelProps
* @prop {Error} error - The error that prevented the client from launching
*/
/**
* An error panel displayed when a fatal error occurs during app startup.
*
* Note that this component cannot use any of the services or store that are
* normally available to UI components in the client.
*
* @param {LaunchErrorPanelProps} props
*/
export default function LaunchErrorPanel({ error }) {
return (
<div className="LaunchErrorPanel">
<Panel title="Unable to start Hypothesis">
<p>{error.message}</p>
</Panel>
</div>
);
}
import { mount } from 'enzyme';
import LaunchErrorPanel from '../LaunchErrorPanel';
describe('LaunchErrorPanel', () => {
// nb. Child components are not mocked here. We need to ensure that the whole
// component tree does not rely on services, the store etc.
it('displays error message', () => {
const error = new Error('Unable to fetch configuration');
const wrapper = mount(<LaunchErrorPanel error={error} />);
assert.include(wrapper.text(), 'Unable to fetch configuration');
});
});
......@@ -101,6 +101,7 @@ registerIcons(iconSet);
// The entry point component for the app.
import { render } from 'preact';
import HypothesisApp from './components/HypothesisApp';
import LaunchErrorPanel from './components/LaunchErrorPanel';
import { ServiceContext } from './service-context';
// Services.
......@@ -133,7 +134,7 @@ import store from './store';
// Utilities.
import { Injector } from '../shared/injector';
function startApp(config) {
function startApp(config, appEl) {
const container = new Injector();
// Register services.
......@@ -179,9 +180,6 @@ function startApp(config) {
container.run(setupFrameSync);
// Render the UI.
const appEl = /** @type {HTMLElement} */ (document.querySelector(
'hypothesis-app'
));
render(
<ServiceContext.Provider value={container}>
<HypothesisApp />
......@@ -190,15 +188,23 @@ function startApp(config) {
);
}
const appEl = /** @type {HTMLElement} */ (document.querySelector(
'hypothesis-app'
));
// Start capturing RPC requests before we start the RPC server (startRPCServer)
preStartRPCServer();
fetchConfig(appConfig)
.then(config => {
startApp(config);
startApp(config, appEl);
})
.catch(err => {
// Report error. This will be the only notice that the user gets because the
// sidebar does not currently appear at all if the app fails to start.
// Report error. In the sidebar the console log is the only notice the user
// gets because the sidebar does not appear at all if the app fails to start.
console.error('Failed to start Hypothesis client: ', err);
// For apps where the UI is visible (eg. notebook, single-annotation view),
// show an error notice.
render(<LaunchErrorPanel error={err} />, appEl);
});
.LaunchErrorPanel {
margin: 50px 5px;
}
......@@ -32,6 +32,7 @@
@use './components/GroupListItem';
@use './components/HelpPanel';
@use './components/HypothesisApp';
@use './components/LaunchErrorPanel';
@use './components/LoggedOutMessage';
@use './components/MarkdownEditor';
@use './components/MarkdownView';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment