Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/space/core/components/editor/lite-text-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ import React from "react";
// plane imports
import { type EditorRefApi, type ILiteTextEditorProps, LiteTextEditorWithRef, type TFileHandler } from "@plane/editor";
import type { MakeOptional } from "@plane/types";
import { cn } from "@plane/utils";
import { cn, isCommentEmpty } from "@plane/utils";
// helpers
import { getEditorFileHandlers } from "@/helpers/editor.helper";
import { isCommentEmpty } from "@/helpers/string.helper";
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
// local imports
import { EditorMentionsRoot } from "./embeds/mentions";
import { IssueCommentToolbar } from "./toolbar";

type LiteTextEditorWrapperProps = MakeOptional<
Omit<ILiteTextEditorProps, "fileHandler" | "mentionHandler">,
Omit<ILiteTextEditorProps, "fileHandler" | "mentionHandler" | "extendedEditorProps">,
"disabledExtensions" | "flaggedExtensions"
> & {
anchor: string;
Expand Down Expand Up @@ -63,6 +62,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
mentionHandler={{
renderComponent: (props) => <EditorMentionsRoot {...props} />,
}}
extendedEditorProps={{}}
{...rest}
// overriding the containerClassName to add relative class passed
containerClassName={cn(containerClassName, "relative")}
Expand Down
3 changes: 2 additions & 1 deletion apps/space/core/components/editor/rich-text-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
import { EditorMentionsRoot } from "./embeds/mentions";

type RichTextEditorWrapperProps = MakeOptional<
Omit<IRichTextEditorProps, "editable" | "fileHandler" | "mentionHandler">,
Omit<IRichTextEditorProps, "editable" | "fileHandler" | "mentionHandler" | "extendedEditorProps">,
"disabledExtensions" | "flaggedExtensions"
> & {
anchor: string;
Expand Down Expand Up @@ -56,6 +56,7 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
workspaceId,
})}
flaggedExtensions={richTextEditorExtensions.flagged}
extendedEditorProps={{}}
{...rest}
containerClassName={containerClassName}
editorClassName="min-h-[100px] max-h-[200px] border-[0.5px] border-custom-border-300 rounded-md pl-3 py-2 overflow-hidden"
Expand Down
18 changes: 0 additions & 18 deletions apps/space/helpers/string.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,6 @@ export const isEmptyHtmlString = (htmlString: string, allowedHTMLTags: string[]
return cleanText.trim() === "";
};

/**
* @description this function returns whether a comment is empty or not by checking for the following conditions-
* 1. If comment is undefined
* 2. If comment is an empty string
* 3. If comment is "<p></p>"
* @param {string | undefined} comment
* @returns {boolean}
*/
export const isCommentEmpty = (comment: string | undefined): boolean => {
// return true if comment is undefined
if (!comment) return true;
return (
comment?.trim() === "" ||
comment === "<p></p>" ||
isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component", "embed-component"])
);
};

export const replaceUnderscoreIfSnakeCase = (str: string) => str.replace(/_/g, " ");

export const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useCallback, useMemo } from "react";
import { useCallback, useEffect, useMemo } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
Expand All @@ -20,6 +20,7 @@ import { PageRoot, TPageRootConfig, TPageRootHandlers } from "@/components/pages
import { useEditorConfig } from "@/hooks/editor";
import { useEditorAsset } from "@/hooks/store/use-editor-asset";
import { useWorkspace } from "@/hooks/store/use-workspace";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web hooks
import { EPageStoreType, usePage, usePageStore } from "@/plane-web/hooks/store";
// plane web services
Expand All @@ -30,13 +31,17 @@ const workspaceService = new WorkspaceService();
const projectPageService = new ProjectPageService();
const projectPageVersionService = new ProjectPageVersionService();

const storeType = EPageStoreType.PROJECT;

const PageDetailsPage = observer(() => {
// router
const router = useAppRouter();
const { workspaceSlug, projectId, pageId } = useParams();
// store hooks
const { createPage, fetchPageDetails } = usePageStore(EPageStoreType.PROJECT);
const { createPage, fetchPageDetails } = usePageStore(storeType);
const page = usePage({
pageId: pageId?.toString() ?? "",
storeType: EPageStoreType.PROJECT,
storeType,
});
const { getWorkspaceBySlug } = useWorkspace();
const { uploadEditorAsset } = useEditorAsset();
Expand Down Expand Up @@ -88,10 +93,25 @@ const PageDetailsPage = observer(() => {
versionId
);
},
getRedirectionLink: (pageId) => `/${workspaceSlug}/projects/${projectId}/pages/${pageId}`,
restoreVersion: async (pageId, versionId) => {
if (!workspaceSlug || !projectId) return;
await projectPageVersionService.restoreVersion(
workspaceSlug.toString(),
projectId.toString(),
pageId,
versionId
);
},
getRedirectionLink: (pageId) => {
if (pageId) {
return `/${workspaceSlug}/projects/${projectId}/pages/${pageId}`;
} else {
return `/${workspaceSlug}/projects/${projectId}/pages`;
}
},
updateDescription: updateDescription ?? (async () => {}),
}),
[createPage, fetchEntityCallback, id, projectId, updateDescription, workspaceSlug]
[createPage, fetchEntityCallback, id, updateDescription, workspaceSlug, projectId]
);
// page root config
const pageRootConfig: TPageRootConfig = useMemo(
Expand All @@ -115,7 +135,7 @@ const PageDetailsPage = observer(() => {
workspaceSlug: workspaceSlug?.toString() ?? "",
}),
}),
[getEditorFileHandlers, id, projectId, uploadEditorAsset, workspaceId, workspaceSlug]
[getEditorFileHandlers, id, uploadEditorAsset, projectId, workspaceId, workspaceSlug]
);

const webhookConnectionParams: TWebhookConnectionQueryParams = useMemo(
Expand All @@ -127,6 +147,12 @@ const PageDetailsPage = observer(() => {
[projectId, workspaceSlug]
);

useEffect(() => {
if (page?.deleted_at && page?.id) {
router.push(pageRootHandlers.getRedirectionLink());
}
}, [page?.deleted_at, page?.id, router, pageRootHandlers]);

if ((!page || !id) && !pageDetailsError)
return (
<div className="size-full grid place-items-center">
Expand All @@ -150,7 +176,7 @@ const PageDetailsPage = observer(() => {
</div>
);

if (!page) return null;
if (!page || !workspaceSlug || !projectId) return null;

return (
<>
Expand All @@ -160,9 +186,11 @@ const PageDetailsPage = observer(() => {
<PageRoot
config={pageRootConfig}
handlers={pageRootHandlers}
storeType={storeType}
page={page}
webhookConnectionParams={webhookConnectionParams}
workspaceSlug={workspaceSlug?.toString() ?? ""}
workspaceSlug={workspaceSlug.toString()}
projectId={projectId?.toString()}
/>
<IssuePeekOverview />
</div>
Expand Down
1 change: 1 addition & 0 deletions apps/web/ce/components/pages/modals/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./move-page-modal";
export * from "./modals";
15 changes: 15 additions & 0 deletions apps/web/ce/components/pages/modals/modals.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import React from "react";
import { observer } from "mobx-react";
// components
import { EPageStoreType } from "@/plane-web/hooks/store";
// store
import { TPageInstance } from "@/store/pages/base-page";

export type TPageModalsProps = {
page: TPageInstance;
storeType: EPageStoreType;
};

export const PageModals: React.FC<TPageModalsProps> = observer((props) => null);
2 changes: 2 additions & 0 deletions apps/web/ce/hooks/pages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./use-pages-pane-extensions";
export * from "./use-extended-editor-extensions";
20 changes: 20 additions & 0 deletions apps/web/ce/hooks/pages/use-extended-editor-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { IEditorPropsExtended } from "@plane/editor";
import type { TSearchEntityRequestPayload, TSearchResponse } from "@plane/types";
import type { TPageInstance } from "@/store/pages/base-page";
import { EPageStoreType } from "../store";

export type TExtendedEditorExtensionsHookParams = {
workspaceSlug: string;
page: TPageInstance;
storeType: EPageStoreType;
fetchEntity: (payload: TSearchEntityRequestPayload) => Promise<TSearchResponse>;
getRedirectionLink: (pageId?: string) => string;
extensionHandlers?: Map<string, unknown>;
projectId?: string;
};

export type TExtendedEditorExtensionsConfig = IEditorPropsExtended;

export const useExtendedEditorProps = (
_params: TExtendedEditorExtensionsHookParams
): TExtendedEditorExtensionsConfig => ({});
52 changes: 52 additions & 0 deletions apps/web/ce/hooks/pages/use-pages-pane-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useCallback, useMemo, type RefObject } from "react";
import { useSearchParams } from "next/navigation";
import type { EditorRefApi } from "@plane/editor";
import {
PAGE_NAVIGATION_PANE_TAB_KEYS,
PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM,
} from "@/components/pages/navigation-pane";
import { useAppRouter } from "@/hooks/use-app-router";
import { useQueryParams } from "@/hooks/use-query-params";
import type { TPageNavigationPaneTab } from "@/plane-web/components/pages/navigation-pane";
import { INavigationPaneExtension } from "@/plane-web/types/pages/pane-extensions";
import type { TPageInstance } from "@/store/pages/base-page";

export type TPageExtensionHookParams = {
page: TPageInstance;
editorRef: RefObject<EditorRefApi>;
};

export const usePagesPaneExtensions = (_params: TPageExtensionHookParams) => {
const router = useAppRouter();
const { updateQueryParams } = useQueryParams();
const searchParams = useSearchParams();

// Generic navigation pane logic - hook manages feature-specific routing
const navigationPaneQueryParam = searchParams.get(
PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM
) as TPageNavigationPaneTab | null;

const isNavigationPaneOpen =
!!navigationPaneQueryParam && PAGE_NAVIGATION_PANE_TAB_KEYS.includes(navigationPaneQueryParam);

const handleOpenNavigationPane = useCallback(() => {
const updatedRoute = updateQueryParams({
paramsToAdd: { [PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM]: "outline" },
});
router.push(updatedRoute);
}, [router, updateQueryParams]);

const editorExtensionHandlers: Map<string, unknown> = useMemo(() => {
const map: Map<string, unknown> = new Map();
return map;
}, []);

const navigationPaneExtensions: INavigationPaneExtension[] = [];

return {
editorExtensionHandlers,
navigationPaneExtensions,
handleOpenNavigationPane,
isNavigationPaneOpen,
};
};
8 changes: 7 additions & 1 deletion apps/web/ce/hooks/use-editor-flagging.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// editor
import type { TExtensions } from "@plane/editor";
import { EPageStoreType } from "@/plane-web/hooks/store";

export type TEditorFlaggingHookReturnType = {
document: {
Expand All @@ -16,10 +17,15 @@ export type TEditorFlaggingHookReturnType = {
};
};

export type TEditorFlaggingHookProps = {
workspaceSlug: string;
storeType?: EPageStoreType;
};

/**
* @description extensions disabled in various editors
*/
export const useEditorFlagging = (workspaceSlug: string): TEditorFlaggingHookReturnType => ({
export const useEditorFlagging = (props: TEditorFlaggingHookProps): TEditorFlaggingHookReturnType => ({
document: {
disabled: ["ai", "collaboration-cursor"],
flagged: [],
Expand Down
16 changes: 16 additions & 0 deletions apps/web/ce/types/pages/pane-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {
type INavigationPaneExtension as ICoreNavigationPaneExtension,
type INavigationPaneExtensionComponent,
} from "@/components/pages/navigation-pane";

// EE Union/map of extension data types (keyed by extension id)
export type TNavigationPaneExtensionData = Record<string, unknown>;

// EE Navigation pane extension configuration
export interface INavigationPaneExtension<
T extends keyof TNavigationPaneExtensionData = keyof TNavigationPaneExtensionData,
> extends Omit<ICoreNavigationPaneExtension<TNavigationPaneExtensionData[T]>, "id" | "data" | "component"> {
id: T;
component: INavigationPaneExtensionComponent<TNavigationPaneExtensionData[T]>;
data?: TNavigationPaneExtensionData[T];
}
7 changes: 5 additions & 2 deletions apps/web/core/components/editor/document/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useIssueEmbed } from "@/plane-web/hooks/use-issue-embed";
import { EditorMentionsRoot } from "../embeds/mentions";

type DocumentEditorWrapperProps = MakeOptional<
Omit<IDocumentEditorProps, "fileHandler" | "mentionHandler" | "embedHandler" | "user">,
Omit<IDocumentEditorProps, "fileHandler" | "mentionHandler" | "embedHandler" | "user" | "extendedEditorProps">,
"disabledExtensions" | "editable" | "flaggedExtensions"
> & {
embedHandler?: Partial<IDocumentEditorProps["embedHandler"]>;
Expand Down Expand Up @@ -45,7 +45,9 @@ export const DocumentEditor = forwardRef<EditorRefApi, DocumentEditorWrapperProp
// store hooks
const { getUserDetails } = useMember();
// editor flaggings
const { document: documentEditorExtensions } = useEditorFlagging(workspaceSlug);
const { document: documentEditorExtensions } = useEditorFlagging({
workspaceSlug: workspaceSlug?.toString() ?? "",
});
// use editor mention
const { fetchMentions } = useEditorMention({
searchEntity: editable ? async (payload) => await props.searchMentionCallback(payload) : async () => ({}),
Expand Down Expand Up @@ -83,6 +85,7 @@ export const DocumentEditor = forwardRef<EditorRefApi, DocumentEditorWrapperProp
issue: issueEmbedProps,
...embedHandler,
}}
extendedEditorProps={{}}
{...rest}
containerClassName={cn("relative pl-3 pb-3", containerClassName)}
/>
Expand Down
7 changes: 5 additions & 2 deletions apps/web/core/components/editor/lite-text/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { WorkspaceService } from "@/plane-web/services";
const workspaceService = new WorkspaceService();

type LiteTextEditorWrapperProps = MakeOptional<
Omit<ILiteTextEditorProps, "fileHandler" | "mentionHandler">,
Omit<ILiteTextEditorProps, "fileHandler" | "mentionHandler" | "extendedEditorProps">,
"disabledExtensions" | "flaggedExtensions"
> & {
workspaceSlug: string;
Expand Down Expand Up @@ -68,7 +68,9 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
// states
const [isFocused, setIsFocused] = useState(showToolbarInitially);
// editor flaggings
const { liteText: liteTextEditorExtensions } = useEditorFlagging(workspaceSlug?.toString());
const { liteText: liteTextEditorExtensions } = useEditorFlagging({
workspaceSlug: workspaceSlug?.toString() ?? "",
});
// store hooks
const { getUserDetails } = useMember();
// use editor mention
Expand Down Expand Up @@ -126,6 +128,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
containerClassName={cn(containerClassName, "relative", {
"p-2": !editable,
})}
extendedEditorProps={{}}
{...rest}
/>
{showToolbar && editable && (
Expand Down
7 changes: 5 additions & 2 deletions apps/web/core/components/editor/rich-text/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useMember } from "@/hooks/store/use-member";
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";

type RichTextEditorWrapperProps = MakeOptional<
Omit<IRichTextEditorProps, "fileHandler" | "mentionHandler">,
Omit<IRichTextEditorProps, "fileHandler" | "mentionHandler" | "extendedEditorProps">,
"disabledExtensions" | "editable" | "flaggedExtensions"
> & {
workspaceSlug: string;
Expand Down Expand Up @@ -42,7 +42,9 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
// store hooks
const { getUserDetails } = useMember();
// editor flaggings
const { richText: richTextEditorExtensions } = useEditorFlagging(workspaceSlug?.toString());
const { richText: richTextEditorExtensions } = useEditorFlagging({
workspaceSlug: workspaceSlug?.toString() ?? "",
});
// use editor mention
const { fetchMentions } = useEditorMention({
searchEntity: editable ? async (payload) => await props.searchMentionCallback(payload) : async () => ({}),
Expand Down Expand Up @@ -73,6 +75,7 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
display_name: getUserDetails(id)?.display_name ?? "",
}),
}}
extendedEditorProps={{}}
{...rest}
containerClassName={cn("relative pl-3 pb-3", containerClassName)}
/>
Expand Down
Loading
Loading