feat(fork)!: remove all frontend Enterprise-Edition code (community build)

Strip the proprietary client EE so the fork ships a clean community/AGPL
edition, mirroring Forkmost. Delete apps/client/src/ee (201 files) and
packages/ee, and patch every consumer that imported from @/ee/*.

- gate-out EE features (useHasFeature -> false): API keys, SSO, MFA, SCIM,
  audit logs, AI / AI-chat, templates, page permissions, page verification,
  comment resolution, trash retention, viewer comments
- drop cloud/billing/trial/entitlement/posthog flows; sign-in is now
  email+password only (no SSO/LDAP/cloud)
- remove EE routes from App.tsx and EE entries from sidebars/settings nav
- restore the community page-share button (ShareModal) that the EE
  PageShareModal used to provide
- remove the dead "Attachments" search filter, dead MFA navigation and
  orphaned route constants

Client type-checks clean; full `pnpm build` is green for all three projects.
This commit is contained in:
vvzvlad
2026-06-16 22:32:39 +03:00
parent 4f05fb5d2e
commit a88b3f776c
240 changed files with 189 additions and 21012 deletions
@@ -7,15 +7,11 @@ import CommentEditor from "@/features/comment/components/comment-editor";
import { pageEditorAtom } from "@/features/editor/atoms/editor-atoms";
import CommentActions from "@/features/comment/components/comment-actions";
import CommentMenu from "@/features/comment/components/comment-menu";
import { useHasFeature } from "@/ee/hooks/use-feature";
import { Feature } from "@/ee/features";
import ResolveComment from "@/ee/comment/components/resolve-comment";
import { useHover } from "@mantine/hooks";
import {
useDeleteCommentMutation,
useUpdateCommentMutation,
} from "@/features/comment/queries/comment-query";
import { useResolveCommentMutation } from "@/ee/comment/queries/comment-query";
import { IComment } from "@/features/comment/types/comment.types";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
@@ -43,9 +39,7 @@ function CommentListItem({
const editContentRef = useRef<any>(null);
const updateCommentMutation = useUpdateCommentMutation();
const deleteCommentMutation = useDeleteCommentMutation(comment.pageId);
const resolveCommentMutation = useResolveCommentMutation();
const [currentUser] = useAtom(currentUserAtom);
const canResolve = useHasFeature(Feature.COMMENT_RESOLUTION);
const createdAtAgo = useTimeAgo(comment.createdAt);
useEffect(() => {
@@ -81,26 +75,6 @@ function CommentListItem({
}
}
async function handleResolveComment() {
if (!canResolve) return;
try {
const isResolved = comment.resolvedAt != null;
await resolveCommentMutation.mutateAsync({
commentId: comment.id,
pageId: comment.pageId,
resolved: !isResolved,
});
if (editor) {
editor.commands.setCommentResolved(comment.id, !isResolved);
}
} catch (error) {
console.error("Failed to toggle resolved state:", error);
}
}
function handleCommentClick(comment: IComment) {
const el = document.querySelector(
`.comment-mark[data-comment-id="${comment.id}"]`,
@@ -138,23 +112,11 @@ function CommentListItem({
</Text>
<div style={{ visibility: hovered ? "visible" : "hidden" }}>
{!comment.parentCommentId && canComment && canResolve && (
<ResolveComment
editor={editor}
commentId={comment.id}
pageId={comment.pageId}
resolvedAt={comment.resolvedAt}
/>
)}
{(currentUser?.user?.id === comment.creatorId || userSpaceRole === 'admin') && (
<CommentMenu
onEditComment={handleEditToggle}
onDeleteComment={handleDeleteComment}
onResolveComment={handleResolveComment}
canEdit={currentUser?.user?.id === comment.creatorId}
isResolved={comment.resolvedAt != null}
isParentComment={!comment.parentCommentId}
/>
)}
</div>
@@ -1,37 +1,20 @@
import { ActionIcon, Menu, Tooltip } from "@mantine/core";
import {
IconDots,
IconEdit,
IconTrash,
IconCircleCheck,
IconCircleCheckFilled,
} from "@tabler/icons-react";
import { ActionIcon, Menu } from "@mantine/core";
import { IconDots, IconEdit, IconTrash } from "@tabler/icons-react";
import { modals } from "@mantine/modals";
import { useTranslation } from "react-i18next";
import { useHasFeature } from "@/ee/hooks/use-feature";
import { Feature } from "@/ee/features";
import { useUpgradeLabel } from "@/ee/hooks/use-upgrade-label";
type CommentMenuProps = {
onEditComment: () => void;
onDeleteComment: () => void;
onResolveComment?: () => void;
canEdit?: boolean;
isResolved?: boolean;
isParentComment?: boolean;
};
function CommentMenu({
onEditComment,
onDeleteComment,
onResolveComment,
canEdit = true,
isResolved = false,
isParentComment = false,
}: CommentMenuProps) {
const { t } = useTranslation();
const canResolve = useHasFeature(Feature.COMMENT_RESOLUTION);
const upgradeLabel = useUpgradeLabel();
//@ts-ignore
const openDeleteModal = () =>
@@ -64,27 +47,6 @@ function CommentMenu({
{t("Edit comment")}
</Menu.Item>
)}
{isParentComment &&
(canResolve ? (
<Menu.Item
onClick={onResolveComment}
leftSection={
isResolved ? (
<IconCircleCheckFilled size={14} />
) : (
<IconCircleCheck size={14} />
)
}
>
{isResolved ? t("Re-open comment") : t("Resolve comment")}
</Menu.Item>
) : (
<Tooltip label={upgradeLabel} position="left" withinPortal={false}>
<Menu.Item disabled leftSection={<IconCircleCheck size={14} />}>
{t("Resolve comment")}
</Menu.Item>
</Tooltip>
))}
<Menu.Item
leftSection={<IconTrash size={14} />}
onClick={openDeleteModal}