diff --git a/src/app/app.less b/src/app/app.less
index fdd9dd781..da93e0f66 100644
--- a/src/app/app.less
+++ b/src/app/app.less
@@ -373,6 +373,15 @@ a.a-block {
}
}
+.load-error-text {
+ color: @term-red;
+ padding-top: 5px;
+}
+
+.view-error {
+ padding: 10px 20px;
+}
+
@keyframes loader-ring {
0% {
transform: rotate(0deg);
diff --git a/src/app/app.tsx b/src/app/app.tsx
index 4038440f7..003ad822e 100644
--- a/src/app/app.tsx
+++ b/src/app/app.tsx
@@ -24,6 +24,7 @@ import { TosModal } from "./common/modals/modals";
import { WorkspaceView } from "../app/workspace/workspaceview";
import { MainSideBar } from "./sidebar/MainSideBar";
import { DisconnectedModal, ClientStopModal, AlertModal, WelcomeModal } from "./common/modals/modals";
+import { ErrorBoundary } from "./common/error/errorboundary";
import "./app.less";
dayjs.extend(localizedFormat);
@@ -110,9 +111,11 @@ class App extends React.Component<{}, {}> {
-
-
-
+
+
+
+
+
diff --git a/src/app/common/error/errorboundary.tsx b/src/app/common/error/errorboundary.tsx
new file mode 100644
index 000000000..a87998fd7
--- /dev/null
+++ b/src/app/common/error/errorboundary.tsx
@@ -0,0 +1,65 @@
+import React, { Component, ReactNode } from "react";
+import { RendererContext } from "../../../plugins/types/types";
+import cn from "classnames";
+
+interface ErrorBoundaryState {
+ hasError: boolean;
+ error: Error | null;
+}
+
+interface ErrorBoundaryProps {
+ children: ReactNode;
+ plugin?: string;
+ lineContext?: RendererContext;
+}
+
+class ErrorBoundary extends Component {
+ state: ErrorBoundaryState = {
+ hasError: false,
+ error: null,
+ };
+
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
+ const { plugin, lineContext } = this.props;
+
+ if (plugin && lineContext) {
+ console.log(`Plugin Name: ${plugin}\n`);
+ console.log(`Line Context: \n`);
+ console.log(`${JSON.stringify(lineContext, null, 4)}\n`);
+ }
+
+ console.log(error);
+ }
+
+ resetErrorBoundary = (): void => {
+ this.setState({ hasError: false, error: null });
+ };
+
+ renderFallback() {
+ const { error } = this.state;
+ const { plugin } = this.props;
+
+ return (
+
+
{`${error?.message}`}
+ {plugin &&
An error occurred in the {plugin} plugin
}
+
+ );
+ }
+
+ render() {
+ const { hasError } = this.state;
+
+ if (hasError) {
+ return this.renderFallback();
+ }
+
+ return this.props.children;
+ }
+}
+
+export { ErrorBoundary };
diff --git a/src/app/line/linecomps.tsx b/src/app/line/linecomps.tsx
index 7a604e1a9..598307db6 100644
--- a/src/app/line/linecomps.tsx
+++ b/src/app/line/linecomps.tsx
@@ -38,6 +38,7 @@ import { isBlank } from "../../util/util";
import { PluginModel } from "../../plugins/plugins";
import { Prompt } from "../common/prompt/prompt";
import * as lineutil from "./lineutil";
+import { ErrorBoundary } from "../../app/common/error/errorboundary";
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
import { ReactComponent as CommentIcon } from "../assets/icons/line/comment.svg";
@@ -594,7 +595,6 @@ class LineCmd extends React.Component<
let isRunning = cmd.isRunning();
let isExpanded = this.isCmdExpanded.get();
let rsdiff = this.rtnStateDiff.get();
- // console.log("render", "#" + line.linenum, termHeight, usedRows, cmd.getStatus(), (this.rtnStateDiff.get() != null), (!cmd.isRunning() ? "cmd-done" : "running"));
let mainDivCn = cn(
"line",
"line-cmd",
@@ -664,39 +664,41 @@ class LineCmd extends React.Component<
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
{
cmdInputHeight = 110;
}
let isHidden = GlobalModel.activeMainView.get() != "session";
+
return (
);
}