mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
errorboundary fallback, errorboundary in block frame header. fix workspace error boundary
This commit is contained in:
parent
639e796296
commit
766a976718
@ -28,6 +28,7 @@ import {
|
|||||||
} from "@/app/store/global";
|
} from "@/app/store/global";
|
||||||
import * as services from "@/app/store/services";
|
import * as services from "@/app/store/services";
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
|
import { ErrorBoundary } from "@/element/errorboundary";
|
||||||
import { IconButton } from "@/element/iconbutton";
|
import { IconButton } from "@/element/iconbutton";
|
||||||
import { MagnifyIcon } from "@/element/magnify";
|
import { MagnifyIcon } from "@/element/magnify";
|
||||||
import { NodeModel } from "@/layout/index";
|
import { NodeModel } from "@/layout/index";
|
||||||
@ -116,7 +117,7 @@ function computeEndIcons(
|
|||||||
onContextMenu: (e: React.MouseEvent<HTMLDivElement>) => void
|
onContextMenu: (e: React.MouseEvent<HTMLDivElement>) => void
|
||||||
): JSX.Element[] {
|
): JSX.Element[] {
|
||||||
const endIconsElem: JSX.Element[] = [];
|
const endIconsElem: JSX.Element[] = [];
|
||||||
const endIconButtons = util.useAtomValueSafe(viewModel.endIconButtons);
|
const endIconButtons = util.useAtomValueSafe(viewModel?.endIconButtons);
|
||||||
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
||||||
const numLeafs = jotai.useAtomValue(nodeModel.numLeafs);
|
const numLeafs = jotai.useAtomValue(nodeModel.numLeafs);
|
||||||
const magnifyDisabled = numLeafs <= 1;
|
const magnifyDisabled = numLeafs <= 1;
|
||||||
@ -155,15 +156,16 @@ const BlockFrame_Header = ({
|
|||||||
preview,
|
preview,
|
||||||
connBtnRef,
|
connBtnRef,
|
||||||
changeConnModalAtom,
|
changeConnModalAtom,
|
||||||
}: BlockFrameProps & { changeConnModalAtom: jotai.PrimitiveAtom<boolean> }) => {
|
error,
|
||||||
|
}: BlockFrameProps & { changeConnModalAtom: jotai.PrimitiveAtom<boolean>; error?: Error }) => {
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
||||||
const viewName = util.useAtomValueSafe(viewModel.viewName) ?? blockViewToName(blockData?.meta?.view);
|
const viewName = util.useAtomValueSafe(viewModel?.viewName) ?? blockViewToName(blockData?.meta?.view);
|
||||||
const showBlockIds = jotai.useAtomValue(useSettingsKeyAtom("blockheader:showblockids"));
|
const showBlockIds = jotai.useAtomValue(useSettingsKeyAtom("blockheader:showblockids"));
|
||||||
const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
const viewIconUnion = util.useAtomValueSafe(viewModel?.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
||||||
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
const preIconButton = util.useAtomValueSafe(viewModel?.preIconButton);
|
||||||
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
const headerTextUnion = util.useAtomValueSafe(viewModel?.viewText);
|
||||||
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
||||||
const manageConnection = util.useAtomValueSafe(viewModel.manageConnection);
|
const manageConnection = util.useAtomValueSafe(viewModel?.manageConnection);
|
||||||
const dragHandleRef = preview ? null : nodeModel.dragHandleRef;
|
const dragHandleRef = preview ? null : nodeModel.dragHandleRef;
|
||||||
|
|
||||||
const onContextMenu = React.useCallback(
|
const onContextMenu = React.useCallback(
|
||||||
@ -193,6 +195,19 @@ const BlockFrame_Header = ({
|
|||||||
headerTextElems.push(...renderHeaderElements(headerTextUnion, preview));
|
headerTextElems.push(...renderHeaderElements(headerTextUnion, preview));
|
||||||
}
|
}
|
||||||
headerTextElems.unshift(<ControllerStatusIcon key="connstatus" blockId={nodeModel.blockId} />);
|
headerTextElems.unshift(<ControllerStatusIcon key="connstatus" blockId={nodeModel.blockId} />);
|
||||||
|
if (error != null) {
|
||||||
|
const copyHeaderErr = () => {
|
||||||
|
navigator.clipboard.writeText(error.message + "\n" + error.stack);
|
||||||
|
};
|
||||||
|
headerTextElems.push(
|
||||||
|
<div className="iconbutton disabled" key="controller-status" onClick={copyHeaderErr}>
|
||||||
|
<i
|
||||||
|
className="fa-sharp fa-solid fa-triangle-exclamation"
|
||||||
|
title={"Error Rendering View Header: " + error.message}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="block-frame-default-header" ref={dragHandleRef} onContextMenu={onContextMenu}>
|
<div className="block-frame-default-header" ref={dragHandleRef} onContextMenu={onContextMenu}>
|
||||||
@ -377,9 +392,9 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
const { nodeModel, viewModel, blockModel, preview, numBlocksInTab, children } = props;
|
const { nodeModel, viewModel, blockModel, preview, numBlocksInTab, children } = props;
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
||||||
const isFocused = jotai.useAtomValue(nodeModel.isFocused);
|
const isFocused = jotai.useAtomValue(nodeModel.isFocused);
|
||||||
const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
const viewIconUnion = util.useAtomValueSafe(viewModel?.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
||||||
const customBg = util.useAtomValueSafe(viewModel.blockBg);
|
const customBg = util.useAtomValueSafe(viewModel?.blockBg);
|
||||||
const manageConnection = util.useAtomValueSafe(viewModel.manageConnection);
|
const manageConnection = util.useAtomValueSafe(viewModel?.manageConnection);
|
||||||
const changeConnModalAtom = useBlockAtom(nodeModel.blockId, "changeConn", () => {
|
const changeConnModalAtom = useBlockAtom(nodeModel.blockId, "changeConn", () => {
|
||||||
return jotai.atom(false);
|
return jotai.atom(false);
|
||||||
}) as jotai.PrimitiveAtom<boolean>;
|
}) as jotai.PrimitiveAtom<boolean>;
|
||||||
@ -429,6 +444,10 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const previewElem = <div className="block-frame-preview">{viewIconElem}</div>;
|
const previewElem = <div className="block-frame-preview">{viewIconElem}</div>;
|
||||||
|
const headerElem = (
|
||||||
|
<BlockFrame_Header {...props} connBtnRef={connBtnRef} changeConnModalAtom={changeConnModalAtom} />
|
||||||
|
);
|
||||||
|
const headerElemNoView = React.cloneElement(headerElem, { viewModel: null });
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx("block", "block-frame-default", "block-" + nodeModel.blockId, {
|
className={clsx("block", "block-frame-default", "block-" + nodeModel.blockId, {
|
||||||
@ -442,7 +461,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
ref={blockModel?.blockRef}
|
ref={blockModel?.blockRef}
|
||||||
>
|
>
|
||||||
<BlockMask nodeModel={nodeModel} />
|
<BlockMask nodeModel={nodeModel} />
|
||||||
{preview ? null : (
|
{preview || viewModel == null ? null : (
|
||||||
<ConnStatusOverlay
|
<ConnStatusOverlay
|
||||||
nodeModel={nodeModel}
|
nodeModel={nodeModel}
|
||||||
viewModel={viewModel}
|
viewModel={viewModel}
|
||||||
@ -450,10 +469,10 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="block-frame-default-inner" style={innerStyle}>
|
<div className="block-frame-default-inner" style={innerStyle}>
|
||||||
<BlockFrame_Header {...props} connBtnRef={connBtnRef} changeConnModalAtom={changeConnModalAtom} />
|
<ErrorBoundary fallback={headerElemNoView}>{headerElem}</ErrorBoundary>
|
||||||
{preview ? previewElem : children}
|
{preview ? previewElem : children}
|
||||||
</div>
|
</div>
|
||||||
{preview || !connModalOpen ? null : (
|
{preview || viewModel == null || !connModalOpen ? null : (
|
||||||
<ChangeConnectionBlockModal
|
<ChangeConnectionBlockModal
|
||||||
blockId={nodeModel.blockId}
|
blockId={nodeModel.blockId}
|
||||||
nodeModel={nodeModel}
|
nodeModel={nodeModel}
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
export class ErrorBoundary extends React.Component<{ children: ReactNode }, { error: Error }> {
|
export class ErrorBoundary extends React.Component<
|
||||||
|
{ children: ReactNode; fallback?: React.ReactElement & { error?: Error } },
|
||||||
|
{ error: Error }
|
||||||
|
> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { error: null };
|
this.state = { error: null };
|
||||||
@ -14,8 +17,12 @@ export class ErrorBoundary extends React.Component<{ children: ReactNode }, { er
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { fallback } = this.props;
|
||||||
const { error } = this.state;
|
const { error } = this.state;
|
||||||
if (error) {
|
if (error) {
|
||||||
|
if (fallback != null) {
|
||||||
|
return React.cloneElement(fallback as any, { error });
|
||||||
|
}
|
||||||
const errorMsg = `Error: ${error?.message}\n\n${error?.stack}`;
|
const errorMsg = `Error: ${error?.message}\n\n${error?.stack}`;
|
||||||
return <pre className="error-boundary">{errorMsg}</pre>;
|
return <pre className="error-boundary">{errorMsg}</pre>;
|
||||||
} else {
|
} else {
|
||||||
|
@ -108,7 +108,7 @@ const WorkspaceElem = React.memo(() => {
|
|||||||
<div className="workspace">
|
<div className="workspace">
|
||||||
<TabBar key={ws.oid} workspace={ws} />
|
<TabBar key={ws.oid} workspace={ws} />
|
||||||
<div className="workspace-tabcontent">
|
<div className="workspace-tabcontent">
|
||||||
<ErrorBoundary>
|
<ErrorBoundary key={activeTabId}>
|
||||||
{activeTabId == "" ? (
|
{activeTabId == "" ? (
|
||||||
<CenteredDiv>No Active Tab</CenteredDiv>
|
<CenteredDiv>No Active Tab</CenteredDiv>
|
||||||
) : (
|
) : (
|
||||||
|
Loading…
Reference in New Issue
Block a user