mirror of
https://github.com/docmost/docmost.git
synced 2026-08-25 01:32:13 +10:00
fix: comment error boundary
This commit is contained in:
@@ -83,6 +83,7 @@
|
|||||||
"Failed to restore page": "Failed to restore page",
|
"Failed to restore page": "Failed to restore page",
|
||||||
"Failed to fetch recent pages": "Failed to fetch recent pages",
|
"Failed to fetch recent pages": "Failed to fetch recent pages",
|
||||||
"Failed to import pages": "Failed to import pages",
|
"Failed to import pages": "Failed to import pages",
|
||||||
|
"Failed to load comments. An error occurred.": "Failed to load comments. An error occurred.",
|
||||||
"Failed to load page. An error occurred.": "Failed to load page. An error occurred.",
|
"Failed to load page. An error occurred.": "Failed to load page. An error occurred.",
|
||||||
"Failed to update data": "Failed to update data",
|
"Failed to update data": "Failed to update data",
|
||||||
"Failed to create base": "Failed to create base",
|
"Failed to create base": "Failed to create base",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ActionIcon, Box, Group, ScrollArea, Title, Tooltip } from "@mantine/core";
|
import { ActionIcon, Box, Group, ScrollArea, Title, Tooltip } from "@mantine/core";
|
||||||
import { IconX } from "@tabler/icons-react";
|
import { IconX } from "@tabler/icons-react";
|
||||||
import CommentListWithTabs from "@/features/comment/components/comment-list-with-tabs.tsx";
|
import CommentListWithTabs from "@/features/comment/components/comment-list-with-tabs.tsx";
|
||||||
|
import { CommentErrorBoundary } from "@/features/comment/components/comment-error-boundary.tsx";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
||||||
import React, { ReactNode, useEffect } from "react";
|
import React, { ReactNode, useEffect } from "react";
|
||||||
@@ -28,7 +29,11 @@ export default function Aside() {
|
|||||||
|
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case "comments":
|
case "comments":
|
||||||
component = <CommentListWithTabs />;
|
component = (
|
||||||
|
<CommentErrorBoundary>
|
||||||
|
<CommentListWithTabs />
|
||||||
|
</CommentErrorBoundary>
|
||||||
|
);
|
||||||
title = "Comments";
|
title = "Comments";
|
||||||
break;
|
break;
|
||||||
case "toc":
|
case "toc":
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from "@/features/comment/atoms/comment-atom";
|
} from "@/features/comment/atoms/comment-atom";
|
||||||
import CommentEditor from "@/features/comment/components/comment-editor";
|
import CommentEditor from "@/features/comment/components/comment-editor";
|
||||||
import CommentActions from "@/features/comment/components/comment-actions";
|
import CommentActions from "@/features/comment/components/comment-actions";
|
||||||
|
import { CommentErrorBoundary } from "@/features/comment/components/comment-error-boundary";
|
||||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
||||||
import { useCreateCommentMutation } from "@/features/comment/queries/comment-query";
|
import { useCreateCommentMutation } from "@/features/comment/queries/comment-query";
|
||||||
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom";
|
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom";
|
||||||
@@ -170,14 +171,16 @@ function CommentDialog({ editor, pageId, readOnly }: CommentDialogProps) {
|
|||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<CommentEditor
|
<CommentErrorBoundary>
|
||||||
onUpdate={handleCommentEditorChange}
|
<CommentEditor
|
||||||
onSave={handleAddComment}
|
onUpdate={handleCommentEditorChange}
|
||||||
placeholder={t("Write a comment")}
|
onSave={handleAddComment}
|
||||||
editable={true}
|
placeholder={t("Write a comment")}
|
||||||
autofocus={true}
|
editable={true}
|
||||||
/>
|
autofocus={true}
|
||||||
<CommentActions onSave={handleAddComment} isLoading={isPending} />
|
/>
|
||||||
|
<CommentActions onSave={handleAddComment} isLoading={isPending} />
|
||||||
|
</CommentErrorBoundary>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ import { Color } from "@tiptap/extension-color";
|
|||||||
import {
|
import {
|
||||||
Mention,
|
Mention,
|
||||||
LinkExtension,
|
LinkExtension,
|
||||||
CustomTable,
|
|
||||||
TableRow,
|
|
||||||
TableCell,
|
|
||||||
TableHeader,
|
|
||||||
TableView,
|
|
||||||
TiptapImage,
|
TiptapImage,
|
||||||
SharedStorage,
|
SharedStorage,
|
||||||
|
Attachment,
|
||||||
} from "@docmost/editor-ext";
|
} from "@docmost/editor-ext";
|
||||||
import ImageView from "@/features/editor/components/image/image-view";
|
import ImageView from "@/features/editor/components/image/image-view";
|
||||||
import classes from "./comment.module.css";
|
import classes from "./comment.module.css";
|
||||||
@@ -24,6 +20,8 @@ import EmojiCommand from "@/features/editor/extensions/emoji-command";
|
|||||||
import mentionRenderItems from "@/features/editor/components/mention/mention-suggestion";
|
import mentionRenderItems from "@/features/editor/components/mention/mention-suggestion";
|
||||||
import MentionView from "@/features/editor/components/mention/mention-view";
|
import MentionView from "@/features/editor/components/mention/mention-view";
|
||||||
import { platformModifierKey } from "@/lib";
|
import { platformModifierKey } from "@/lib";
|
||||||
|
import { TableKit } from "@tiptap/extension-table";
|
||||||
|
import AttachmentView from "@/features/editor/components/attachment/attachment-view.tsx";
|
||||||
|
|
||||||
interface CommentEditorProps {
|
interface CommentEditorProps {
|
||||||
defaultContent?: any;
|
defaultContent?: any;
|
||||||
@@ -81,14 +79,11 @@ const CommentEditor = forwardRef(
|
|||||||
return ReactNodeViewRenderer(MentionView);
|
return ReactNodeViewRenderer(MentionView);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
SharedStorage,
|
TableKit,
|
||||||
CustomTable.configure({
|
Attachment.configure({
|
||||||
resizable: false,
|
view: AttachmentView,
|
||||||
View: TableView,
|
|
||||||
}),
|
}),
|
||||||
TableRow,
|
SharedStorage,
|
||||||
TableCell,
|
|
||||||
TableHeader,
|
|
||||||
TiptapImage.configure({
|
TiptapImage.configure({
|
||||||
view: ImageView,
|
view: ImageView,
|
||||||
allowBase64: false,
|
allowBase64: false,
|
||||||
@@ -139,7 +134,12 @@ const CommentEditor = forwardRef(
|
|||||||
// websocket on another browser). Skip for editable editors to avoid
|
// websocket on another browser). Skip for editable editors to avoid
|
||||||
// resetting the cursor position on every keystroke.
|
// resetting the cursor position on every keystroke.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editable && commentEditor && !commentEditor.isDestroyed && defaultContent) {
|
if (
|
||||||
|
!editable &&
|
||||||
|
commentEditor &&
|
||||||
|
!commentEditor.isDestroyed &&
|
||||||
|
defaultContent
|
||||||
|
) {
|
||||||
commentEditor.commands.setContent(defaultContent);
|
commentEditor.commands.setContent(defaultContent);
|
||||||
}
|
}
|
||||||
}, [defaultContent, editable, commentEditor]);
|
}, [defaultContent, editable, commentEditor]);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ReactNode } from "react";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
|
import { Button } from "@mantine/core";
|
||||||
|
import { IconAlertTriangle } from "@tabler/icons-react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { EmptyState } from "@/components/ui/empty-state.tsx";
|
||||||
|
|
||||||
|
type CommentErrorBoundaryProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Contain comment-editor render throws (e.g. schema errors) so they don't unmount the whole app.
|
||||||
|
export function CommentErrorBoundary({ children }: CommentErrorBoundaryProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ErrorBoundary
|
||||||
|
fallbackRender={({ resetErrorBoundary }) => (
|
||||||
|
<EmptyState
|
||||||
|
icon={IconAlertTriangle}
|
||||||
|
title={t("Failed to load comments. An error occurred.")}
|
||||||
|
action={
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
size="sm"
|
||||||
|
mt="xs"
|
||||||
|
onClick={resetErrorBoundary}
|
||||||
|
>
|
||||||
|
{t("Try again")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user