[PE-182] refactor: pages' components and store for scalability (#6283)

* refactor: created a generic base page instance

* refactor: project store hooks

* chore: add missing prop declaration

* refactor: editor page root and body

* refactor: issue embed hook

* chore: update search entity types

* fix: version editor component

* fix: add page to favorites action

---------

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
This commit is contained in:
Aaryan Khandelwal 2024-12-27 20:41:38 +05:30 committed by GitHub
parent 211d5e1cd0
commit 8d7425a3b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 553 additions and 521 deletions

View file

@ -1,29 +1,58 @@
"use client";
import { useCallback, useMemo } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
import useSWR from "swr";
// ui
// plane types
import { TSearchEntityRequestPayload } from "@plane/types";
import { EFileAssetType } from "@plane/types/src/enums";
// plane ui
import { getButtonStyling } from "@plane/ui";
// plane utils
import { cn } from "@plane/utils";
// components
import { LogoSpinner } from "@/components/common";
import { PageHead } from "@/components/core";
import { IssuePeekOverview } from "@/components/issues";
import { PageRoot } from "@/components/pages";
import { PageRoot, TPageRootConfig, TPageRootHandlers } from "@/components/pages";
// helpers
import { cn } from "@/helpers/common.helper";
import { getEditorFileHandlers } from "@/helpers/editor.helper";
// hooks
import { usePage, useProjectPages } from "@/hooks/store";
import { useProjectPage, useProjectPages, useWorkspace } from "@/hooks/store";
// plane web hooks
import { useFileSize } from "@/plane-web/hooks/use-file-size";
// plane web services
import { WorkspaceService } from "@/plane-web/services";
// services
import { FileService } from "@/services/file.service";
import { ProjectPageService, ProjectPageVersionService } from "@/services/page";
const workspaceService = new WorkspaceService();
const fileService = new FileService();
const projectPageService = new ProjectPageService();
const projectPageVersionService = new ProjectPageVersionService();
const PageDetailsPage = observer(() => {
const { workspaceSlug, projectId, pageId } = useParams();
// store hooks
const { getPageById } = useProjectPages();
const page = usePage(pageId?.toString() ?? "");
const { id, name } = page;
const { createPage, getPageById } = useProjectPages();
const page = useProjectPage(pageId?.toString() ?? "");
const { getWorkspaceBySlug } = useWorkspace();
// derived values
const workspaceId = workspaceSlug ? (getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "") : "";
const { id, name, updateDescription } = page;
// entity search handler
const fetchEntityCallback = useCallback(
async (payload: TSearchEntityRequestPayload) =>
await workspaceService.searchEntity(workspaceSlug?.toString() ?? "", {
...payload,
project_id: projectId?.toString() ?? "",
}),
[projectId, workspaceSlug]
);
// file size
const { maxFileSize } = useFileSize();
// fetch page details
const { error: pageDetailsError } = useSWR(
workspaceSlug && projectId && pageId ? `PAGE_DETAILS_${pageId}` : null,
@ -36,6 +65,62 @@ const PageDetailsPage = observer(() => {
revalidateOnReconnect: true,
}
);
// page root handlers
const pageRootHandlers: TPageRootHandlers = useMemo(
() => ({
create: createPage,
fetchAllVersions: async (pageId) => {
if (!workspaceSlug || !projectId) return;
return await projectPageVersionService.fetchAllVersions(workspaceSlug.toString(), projectId.toString(), pageId);
},
fetchDescriptionBinary: async () => {
if (!workspaceSlug || !projectId || !page.id) return;
return await projectPageService.fetchDescriptionBinary(workspaceSlug.toString(), projectId.toString(), page.id);
},
fetchEntity: fetchEntityCallback,
fetchVersionDetails: async (pageId, versionId) => {
if (!workspaceSlug || !projectId) return;
return await projectPageVersionService.fetchVersionById(
workspaceSlug.toString(),
projectId.toString(),
pageId,
versionId
);
},
getRedirectionLink: (pageId) => `/${workspaceSlug}/projects/${projectId}/pages/${pageId}`,
updateDescription,
}),
[createPage, fetchEntityCallback, page.id, projectId, updateDescription, workspaceSlug]
);
// page root config
const pageRootConfig: TPageRootConfig = useMemo(
() => ({
fileHandler: getEditorFileHandlers({
maxFileSize,
projectId: projectId?.toString() ?? "",
uploadFile: async (file) => {
const { asset_id } = await fileService.uploadProjectAsset(
workspaceSlug?.toString() ?? "",
projectId?.toString() ?? "",
{
entity_identifier: id ?? "",
entity_type: EFileAssetType.PAGE_DESCRIPTION,
},
file
);
return asset_id;
},
workspaceId,
workspaceSlug: workspaceSlug?.toString() ?? "",
}),
webhookConnectionParams: {
documentType: "project_page",
projectId: projectId?.toString() ?? "",
workspaceSlug: workspaceSlug?.toString() ?? "",
},
}),
[id, maxFileSize, projectId, workspaceId, workspaceSlug]
);
if ((!page || !id) && !pageDetailsError)
return (
@ -65,7 +150,12 @@ const PageDetailsPage = observer(() => {
<PageHead title={name} />
<div className="flex h-full flex-col justify-between">
<div className="relative h-full w-full flex-shrink-0 flex flex-col overflow-hidden">
<PageRoot page={page} projectId={projectId.toString()} workspaceSlug={workspaceSlug.toString()} />
<PageRoot
config={pageRootConfig}
handlers={pageRootHandlers}
page={page}
workspaceSlug={workspaceSlug?.toString() ?? ""}
/>
<IssuePeekOverview />
</div>
</div>

View file

@ -15,7 +15,7 @@ import { PageEditInformationPopover } from "@/components/pages";
import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper";
import { getPageName } from "@/helpers/page.helper";
// hooks
import { usePage, useProject, useUser, useUserPermissions } from "@/hooks/store";
import { useProjectPage, useProject, useUser, useUserPermissions } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { PageDetailsHeaderExtraActions } from "@/plane-web/components/pages";
@ -32,7 +32,7 @@ export const PageDetailsHeader = observer(() => {
const [isOpen, setIsOpen] = useState(false);
// store hooks
const { currentProjectDetails, loader } = useProject();
const page = usePage(pageId?.toString() ?? "");
const page = useProjectPage(pageId?.toString() ?? "");
const { name, logo_props, updatePageLogo, owned_by } = page;
const { allowPermissions } = useUserPermissions();
const { data: currentUser } = useUser();
@ -169,7 +169,7 @@ export const PageDetailsHeader = observer(() => {
</Header.LeftItem>
<Header.RightItem>
<PageEditInformationPopover page={page} />
<PageDetailsHeaderExtraActions />
<PageDetailsHeaderExtraActions page={page} />
</Header.RightItem>
</Header>
);

View file

@ -51,11 +51,7 @@ const ProjectPagesPage = observer(() => {
projectId={projectId.toString()}
pageType={currentPageType()}
>
<PagesListRoot
pageType={currentPageType()}
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
/>
<PagesListRoot pageType={currentPageType()} />
</PagesListView>
</>
);