From ede32328e7d5ed01c2ad8add352d5db6ea239043 Mon Sep 17 00:00:00 2001 From: Sonia Zorba Date: Tue, 1 Oct 2024 18:25:12 +0200 Subject: [PATCH] Display server error in the page (#214) --- src/index.tsx | 37 ++++++++++++++++++++++++++++++++----- src/state.ts | 16 +++++++++++----- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 4f2114c..b99da35 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,13 +1,13 @@ -import { ThemeProvider } from "@material-ui/styles"; +import { ThemeProvider, makeStyles } from "@material-ui/styles"; import { Provider, atom } from "jotai"; -import { useSetAtom } from "jotai"; +import { useAtomValue, useSetAtom } from "jotai"; import * as React from "react"; import ReactDOM from "react-dom/client"; import Menu from "./components/Menu"; import Viewer from "./components/Viewer"; import "./codecs/register"; -import { type ImageLayerConfig, type ViewState, addImageAtom, atomWithEffect } from "./state"; +import { type ImageLayerConfig, type ViewState, addImageAtom, atomWithEffect, sourceErrorAtom } from "./state"; import theme from "./theme"; import { defer, typedEmitter } from "./utils"; @@ -26,6 +26,22 @@ export interface VizarrViewer { destroy(): void; } +const useStyles = makeStyles({ + errorContainer: { + position: "fixed", + top: 0, + bottom: 0, + left: 0, + right: 0, + color: "#fff", + display: "flex", + alignItems: "center", + textAlign: "center", + justifyContent: "center", + fontSize: "120%", + }, +}); + export function createViewer(element: HTMLElement, options: { menuOpen?: boolean } = {}): Promise { const ref = React.createRef(); const emitter = typedEmitter(); @@ -36,6 +52,7 @@ export function createViewer(element: HTMLElement, options: { menuOpen?: boolean const { promise, resolve } = defer(); function App() { + const sourceError = useAtomValue(sourceErrorAtom); const addImage = useSetAtom(addImageAtom); const setViewState = useSetAtom(viewStateAtom); React.useImperativeHandle( @@ -53,10 +70,20 @@ export function createViewer(element: HTMLElement, options: { menuOpen?: boolean resolve(ref.current); } }, []); + const classes = useStyles(); return ( <> - - + {sourceError === null && ( + <> + + + + )} + {sourceError !== null && ( +
+

{`Error: server replied with "${sourceError}" when loading the resource`}

+
+ )} ); } diff --git a/src/state.ts b/src/state.ts index 4eefd0a..e856f01 100644 --- a/src/state.ts +++ b/src/state.ts @@ -128,17 +128,23 @@ export type ControllerProps = { layerAtom: PrimitiveAtom>; } & T; +export const sourceErrorAtom = atom(null); + export const sourceInfoAtom = atom[]>([]); export const addImageAtom = atom(null, async (get, set, config: ImageLayerConfig) => { const { createSourceData } = await import("./io"); const id = Math.random().toString(36).slice(2); - const sourceData = await createSourceData(config); - const prevSourceInfo = get(sourceInfoAtom); - if (!sourceData.name) { - sourceData.name = `image_${Object.keys(prevSourceInfo).length}`; + try { + const sourceData = await createSourceData(config); + const prevSourceInfo = get(sourceInfoAtom); + if (!sourceData.name) { + sourceData.name = `image_${Object.keys(prevSourceInfo).length}`; + } + set(sourceInfoAtom, [...prevSourceInfo, { id, ...sourceData }]); + } catch (err) { + set(sourceErrorAtom, (err as Error).message); } - set(sourceInfoAtom, [...prevSourceInfo, { id, ...sourceData }]); }); export const sourceInfoAtomAtoms = splitAtom(sourceInfoAtom);