Display error message on failed WebView page load (#1072)

closes #1023
This commit is contained in:
Evan Simkowitz 2024-10-22 18:17:42 -07:00 committed by GitHub
parent 81a8a7f3eb
commit ec70ce8c91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 16 deletions

View File

@ -9,6 +9,7 @@
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
margin: 0; margin: 0;
user-select: none;
// try to force pixel alignment to prevent // try to force pixel alignment to prevent
// subpixel rendering artifacts // subpixel rendering artifacts
@ -16,6 +17,24 @@
will-change: transform; will-change: transform;
} }
.webview-error {
display: flex;
position: absolute;
background-color: black;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 100;
div {
font-size: x-large;
color: red;
display: flex;
margin: auto;
padding: 30px;
}
}
.block-frame-div-url { .block-frame-div-url {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);

View File

@ -13,7 +13,7 @@ import { fireAndForget } from "@/util/util";
import clsx from "clsx"; import clsx from "clsx";
import { WebviewTag } from "electron"; import { WebviewTag } from "electron";
import { Atom, PrimitiveAtom, atom, useAtomValue } from "jotai"; import { Atom, PrimitiveAtom, atom, useAtomValue } from "jotai";
import React, { memo, useEffect, useState } from "react"; import { Fragment, createRef, memo, useEffect, useRef, useState } from "react";
import "./webview.less"; import "./webview.less";
let webviewPreloadUrl = null; let webviewPreloadUrl = null;
@ -68,8 +68,8 @@ export class WebViewModel implements ViewModel {
this.refreshIcon = atom("rotate-right"); this.refreshIcon = atom("rotate-right");
this.viewIcon = atom("globe"); this.viewIcon = atom("globe");
this.viewName = atom("Web"); this.viewName = atom("Web");
this.urlInputRef = React.createRef<HTMLInputElement>(); this.urlInputRef = createRef<HTMLInputElement>();
this.webviewRef = React.createRef<WebviewTag>(); this.webviewRef = createRef<WebviewTag>();
this.mediaPlaying = atom(false); this.mediaPlaying = atom(false);
this.mediaMuted = atom(false); this.mediaMuted = atom(false);
@ -477,7 +477,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
const defaultSearch = useAtomValue(defaultSearchAtom); const defaultSearch = useAtomValue(defaultSearchAtom);
let metaUrl = blockData?.meta?.url || defaultUrl; let metaUrl = blockData?.meta?.url || defaultUrl;
metaUrl = model.ensureUrlScheme(metaUrl, defaultSearch); metaUrl = model.ensureUrlScheme(metaUrl, defaultSearch);
const metaUrlRef = React.useRef(metaUrl); const metaUrlRef = useRef(metaUrl);
// The initial value of the block metadata URL when the component first renders. Used to set the starting src value for the webview. // The initial value of the block metadata URL when the component first renders. Used to set the starting src value for the webview.
const [metaUrlInitial] = useState(metaUrl); const [metaUrlInitial] = useState(metaUrl);
@ -485,6 +485,8 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
const [webContentsId, setWebContentsId] = useState(null); const [webContentsId, setWebContentsId] = useState(null);
const [domReady, setDomReady] = useState(false); const [domReady, setDomReady] = useState(false);
const [errorText, setErrorText] = useState("");
function setBgColor() { function setBgColor() {
const webview = model.webviewRef.current; const webview = model.webviewRef.current;
if (!webview) { if (!webview) {
@ -532,6 +534,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
return; return;
} }
const navigateListener = (e: any) => { const navigateListener = (e: any) => {
setErrorText("");
model.handleNavigate(e.url); model.handleNavigate(e.url);
}; };
const newWindowHandler = (e: any) => { const newWindowHandler = (e: any) => {
@ -554,7 +557,9 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
if (e.errorCode === -3) { if (e.errorCode === -3) {
console.warn("Suppressed ERR_ABORTED error", e); console.warn("Suppressed ERR_ABORTED error", e);
} else { } else {
console.error(`Failed to load ${e.validatedURL}: ${e.errorDescription}`); const errorMessage = `Failed to load ${e.validatedURL}: ${e.errorDescription}`;
console.error(errorMessage);
setErrorText(errorMessage);
if (onFailLoad) { if (onFailLoad) {
const curUrl = model.webviewRef?.current.getURL(); const curUrl = model.webviewRef?.current.getURL();
onFailLoad(curUrl); onFailLoad(curUrl);
@ -608,6 +613,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
}, []); }, []);
return ( return (
<Fragment>
<webview <webview
id="webview" id="webview"
className="webview" className="webview"
@ -618,7 +624,13 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
preload={getWebviewPreloadUrl()} preload={getWebviewPreloadUrl()}
// @ts-ignore This is a discrepancy between the React typing and the Chromium impl for webviewTag. Chrome webviewTag expects a string, while React expects a boolean. // @ts-ignore This is a discrepancy between the React typing and the Chromium impl for webviewTag. Chrome webviewTag expects a string, while React expects a boolean.
allowpopups="true" allowpopups="true"
></webview> />
{errorText && (
<div className="webview-error">
<div>{errorText}</div>
</div>
)}
</Fragment>
); );
}); });