mirror of
https://github.com/docmost/docmost.git
synced 2026-05-21 01:04:39 +08:00
932c1ad5b7
* Better trash I recently lost a bunch of time editing and searching for pages that were actually in the Trash. Docmost intentionally tries to not link to Trashed pages, but the url of that Trashed page and any inbound links still work. This makes it clearer when a page you are interacting with is in the Trash. - /trash - Refactored banner into `trash-banner.tsx` - Refactored "Restore" modal into `use-restore-page-modal.tsx` - Page (when isDeleted) - Add: `trash-banner.tsx` - Add breadcrumbs: `Parent / Child / Page (Deleted)` - Change: Deleted Pages are read-only - Replace "Move to Trash" with "Restore" in page menu (invokes `use-restore-page-modal`) I tried very hard to keep this simple and re-use existing translation strings wherever possible. * cleanup --------- Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import { useParams } from "react-router-dom";
|
|
import { usePageQuery } from "@/features/page/queries/page-query";
|
|
import { FullEditor } from "@/features/editor/full-editor";
|
|
import HistoryModal from "@/features/page-history/components/history-modal";
|
|
import { Helmet } from "react-helmet-async";
|
|
import PageHeader from "@/features/page/components/header/page-header.tsx";
|
|
import { extractPageSlugId } from "@/lib";
|
|
import { useGetSpaceBySlugQuery } from "@/features/space/queries/space-query.ts";
|
|
import { useTranslation } from "react-i18next";
|
|
import React from "react";
|
|
import { EmptyState } from "@/components/ui/empty-state.tsx";
|
|
import { IconAlertTriangle, IconFileOff } from "@tabler/icons-react";
|
|
import { Button } from "@mantine/core";
|
|
import { Link } from "react-router-dom";
|
|
import { ErrorBoundary } from "react-error-boundary";
|
|
const MemoizedFullEditor = React.memo(FullEditor);
|
|
const MemoizedPageHeader = React.memo(PageHeader);
|
|
const MemoizedHistoryModal = React.memo(HistoryModal);
|
|
|
|
export default function Page() {
|
|
const { t } = useTranslation();
|
|
const { pageSlug } = useParams();
|
|
|
|
return (
|
|
<ErrorBoundary
|
|
resetKeys={[pageSlug]}
|
|
fallbackRender={({ resetErrorBoundary }) => (
|
|
<EmptyState
|
|
icon={IconAlertTriangle}
|
|
title={t("Failed to load page. An error occurred.")}
|
|
action={
|
|
<Button variant="default" size="sm" mt="xs" onClick={resetErrorBoundary}>
|
|
{t("Try again")}
|
|
</Button>
|
|
}
|
|
/>
|
|
)}
|
|
>
|
|
<PageContent pageSlug={pageSlug} />
|
|
</ErrorBoundary>
|
|
);
|
|
}
|
|
|
|
function PageContent({ pageSlug }: { pageSlug: string | undefined }) {
|
|
const { t } = useTranslation();
|
|
|
|
const {
|
|
data: page,
|
|
isLoading,
|
|
isError,
|
|
error,
|
|
} = usePageQuery({ pageId: extractPageSlugId(pageSlug) });
|
|
const { data: space } = useGetSpaceBySlugQuery(page?.space?.slug);
|
|
|
|
const canEdit = !page?.deletedAt && (page?.permissions?.canEdit ?? false);
|
|
const canComment =
|
|
canEdit ||
|
|
(space?.settings?.comments?.allowViewerComments === true);
|
|
|
|
if (isLoading) {
|
|
return <></>;
|
|
}
|
|
|
|
if (isError || !page) {
|
|
if ([401, 403, 404].includes(error?.["status"])) {
|
|
return (
|
|
<EmptyState
|
|
icon={IconFileOff}
|
|
title={t("Page not found")}
|
|
description={t(
|
|
"This page may have been deleted, moved, or you may not have access.",
|
|
)}
|
|
action={
|
|
<Button component={Link} to="/home" variant="default" size="sm" mt="xs">
|
|
{t("Go to homepage")}
|
|
</Button>
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<EmptyState
|
|
icon={IconFileOff}
|
|
title={t("Error fetching page data.")}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (!space) {
|
|
return <></>;
|
|
}
|
|
|
|
return (
|
|
page && (
|
|
<div>
|
|
<Helmet>
|
|
<title>{`${page?.icon || ""} ${page?.title || t("untitled")}`}</title>
|
|
</Helmet>
|
|
|
|
<MemoizedPageHeader readOnly={!canEdit} />
|
|
|
|
<MemoizedFullEditor
|
|
key={page.id}
|
|
pageId={page.id}
|
|
title={page.title}
|
|
content={page.content}
|
|
slugId={page.slugId}
|
|
spaceSlug={page?.space?.slug}
|
|
editable={canEdit}
|
|
creator={page.creator}
|
|
contributors={page.contributors}
|
|
canComment={canComment}
|
|
/>
|
|
<MemoizedHistoryModal pageId={page.id} />
|
|
</div>
|
|
)
|
|
);
|
|
}
|