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); ...@@ -101,6 +101,7 @@ registerIcons(iconSet);
// The entry point component for the app. // The entry point component for the app.
import { render } from 'preact'; import { render } from 'preact';
import HypothesisApp from './components/HypothesisApp'; import HypothesisApp from './components/HypothesisApp';
import LaunchErrorPanel from './components/LaunchErrorPanel';
import { ServiceContext } from './service-context'; import { ServiceContext } from './service-context';
// Services. // Services.
...@@ -133,7 +134,7 @@ import store from './store'; ...@@ -133,7 +134,7 @@ import store from './store';
// Utilities. // Utilities.
import { Injector } from '../shared/injector'; import { Injector } from '../shared/injector';
function startApp(config) { function startApp(config, appEl) {
const container = new Injector(); const container = new Injector();
// Register services. // Register services.
...@@ -179,9 +180,6 @@ function startApp(config) { ...@@ -179,9 +180,6 @@ function startApp(config) {
container.run(setupFrameSync); container.run(setupFrameSync);
// Render the UI. // Render the UI.
const appEl = /** @type {HTMLElement} */ (document.querySelector(
'hypothesis-app'
));
render( render(
<ServiceContext.Provider value={container}> <ServiceContext.Provider value={container}>
<HypothesisApp /> <HypothesisApp />
...@@ -190,15 +188,23 @@ function startApp(config) { ...@@ -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) // Start capturing RPC requests before we start the RPC server (startRPCServer)
preStartRPCServer(); preStartRPCServer();
fetchConfig(appConfig) fetchConfig(appConfig)
.then(config => { .then(config => {
startApp(config); startApp(config, appEl);
}) })
.catch(err => { .catch(err => {
// Report error. This will be the only notice that the user gets because the // Report error. In the sidebar the console log is the only notice the user
// sidebar does not currently appear at all if the app fails to start. // gets because the sidebar does not appear at all if the app fails to start.
console.error('Failed to start Hypothesis client: ', err); 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 @@ ...@@ -32,6 +32,7 @@
@use './components/GroupListItem'; @use './components/GroupListItem';
@use './components/HelpPanel'; @use './components/HelpPanel';
@use './components/HypothesisApp'; @use './components/HypothesisApp';
@use './components/LaunchErrorPanel';
@use './components/LoggedOutMessage'; @use './components/LoggedOutMessage';
@use './components/MarkdownEditor'; @use './components/MarkdownEditor';
@use './components/MarkdownView'; @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