From a3f1e6872f4f768d14899a1e70bbdc14f32e478d Mon Sep 17 00:00:00 2001
From: Kristóf Marussy <kristof@marussy.com>
Date: Sun, 20 Aug 2023 19:41:32 +0200
Subject: feat: improve semantics error reporting

Also makes model seeds cancellable to reduce server load during semantic
analysis.
---
 .../src/editor/AnalysisErrorNotification.tsx       | 74 ++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 subprojects/frontend/src/editor/AnalysisErrorNotification.tsx

(limited to 'subprojects/frontend/src/editor/AnalysisErrorNotification.tsx')

diff --git a/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx b/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx
new file mode 100644
index 00000000..591a3600
--- /dev/null
+++ b/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx
@@ -0,0 +1,74 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+import { reaction } from 'mobx';
+import { type SnackbarKey, useSnackbar } from 'notistack';
+import { useEffect, useState } from 'react';
+
+import type EditorStore from './EditorStore';
+
+function MessageObserver({
+  editorStore,
+}: {
+  editorStore: EditorStore;
+}): React.ReactNode {
+  const [message, setMessage] = useState(
+    editorStore.delayedErrors.semanticsError ?? '',
+  );
+  // Instead of making this component an `observer`,
+  // we only update the message is one is present to make sure that the
+  // disappear animation has a chance to complete.
+  useEffect(
+    () =>
+      reaction(
+        () => editorStore.delayedErrors.semanticsError,
+        (newMessage) => {
+          if (newMessage !== undefined) {
+            setMessage(newMessage);
+          }
+        },
+        { fireImmediately: false },
+      ),
+    [editorStore],
+  );
+  return message;
+}
+
+export default function AnalysisErrorNotification({
+  editorStore,
+}: {
+  editorStore: EditorStore;
+}): null {
+  const { enqueueSnackbar, closeSnackbar } = useSnackbar();
+  useEffect(() => {
+    let key: SnackbarKey | undefined;
+    const disposer = reaction(
+      () => editorStore.delayedErrors.semanticsError !== undefined,
+      (hasError) => {
+        if (hasError) {
+          if (key === undefined) {
+            key = enqueueSnackbar({
+              message: <MessageObserver editorStore={editorStore} />,
+              variant: 'error',
+              persist: true,
+            });
+          }
+        } else if (key !== undefined) {
+          closeSnackbar(key);
+          key = undefined;
+        }
+      },
+      { fireImmediately: true },
+    );
+    return () => {
+      disposer();
+      if (key !== undefined) {
+        closeSnackbar(key);
+      }
+    };
+  }, [editorStore, enqueueSnackbar, closeSnackbar]);
+  return null;
+}
-- 
cgit v1.2.3-54-g00ecf

