From 5fa9943b661d21566dffc4106db770ded2f2a7b2 Mon Sep 17 00:00:00 2001
From: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
Date: Thu, 23 Oct 2025 00:27:16 +0530
Subject: [PATCH] [WEB-5141] chore: project features refactor (#7960)
* chore: project features refactor
* fix: enable/disable condition for toggle
* fix: dependencies
* chore: lint fix
* chore: lint fix
* chore: added fallback exports
---
.../projects/[projectId]/features/page.tsx | 2 +-
.../projects/settings/features-list.tsx | 1 +
.../constants/project/settings/features.tsx | 1 +
.../modals/existing-issues-list-modal.tsx | 10 ++---
.../project/settings/features-list.tsx | 15 +++----
.../components/project/settings/helper.tsx | 41 +++++++++++++++++++
.../core/components/sidebar/add-button.tsx | 2 +-
.../core/components/sidebar/search-button.tsx | 2 +-
apps/web/core/store/project/project.store.ts | 2 +-
.../projects/settings/features-list.tsx | 1 +
10 files changed, 61 insertions(+), 16 deletions(-)
create mode 100644 apps/web/ce/components/projects/settings/features-list.tsx
create mode 100644 apps/web/core/components/project/settings/helper.tsx
create mode 100644 apps/web/ee/components/projects/settings/features-list.tsx
diff --git a/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/features/page.tsx b/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/features/page.tsx
index 40d2bed66..730177e13 100644
--- a/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/features/page.tsx
+++ b/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/features/page.tsx
@@ -6,11 +6,11 @@ import { useParams } from "next/navigation";
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
import { PageHead } from "@/components/core/page-title";
-import { ProjectFeaturesList } from "@/components/project/settings/features-list";
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUserPermissions } from "@/hooks/store/user";
+import { ProjectFeaturesList } from "@/plane-web/components/projects/settings/features-list";
const FeaturesSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
diff --git a/apps/web/ce/components/projects/settings/features-list.tsx b/apps/web/ce/components/projects/settings/features-list.tsx
new file mode 100644
index 000000000..26fc591fd
--- /dev/null
+++ b/apps/web/ce/components/projects/settings/features-list.tsx
@@ -0,0 +1 @@
+export { ProjectFeaturesList } from "@/components/project/settings/features-list";
diff --git a/apps/web/ce/constants/project/settings/features.tsx b/apps/web/ce/constants/project/settings/features.tsx
index b86135f08..380272ea4 100644
--- a/apps/web/ce/constants/project/settings/features.tsx
+++ b/apps/web/ce/constants/project/settings/features.tsx
@@ -13,6 +13,7 @@ export type TProperties = {
isPro: boolean;
isEnabled: boolean;
renderChildren?: (currentProjectDetails: IProject, workspaceSlug: string) => ReactNode;
+ href?: string;
};
type TProjectBaseFeatureKeys = "cycles" | "modules" | "views" | "pages" | "inbox";
diff --git a/apps/web/core/components/core/modals/existing-issues-list-modal.tsx b/apps/web/core/components/core/modals/existing-issues-list-modal.tsx
index 41a8e0688..b8c3eaf8b 100644
--- a/apps/web/core/components/core/modals/existing-issues-list-modal.tsx
+++ b/apps/web/core/components/core/modals/existing-issues-list-modal.tsx
@@ -33,7 +33,7 @@ type Props = {
handleOnSubmit: (data: ISearchIssueResponse[]) => Promise;
workspaceLevelToggle?: boolean;
shouldHideIssue?: (issue: ISearchIssueResponse) => boolean;
- selectedWorkItems?: ISearchIssueResponse[];
+ selectedWorkItemIds?: string[];
workItemSearchServiceCallback?: (params: TProjectIssuesSearchParams) => Promise;
};
@@ -51,7 +51,7 @@ export const ExistingIssuesListModal: React.FC = (props) => {
handleOnSubmit,
workspaceLevelToggle = false,
shouldHideIssue,
- selectedWorkItems,
+ selectedWorkItemIds,
workItemSearchServiceCallback,
} = props;
// states
@@ -117,10 +117,10 @@ export const ExistingIssuesListModal: React.FC = (props) => {
};
useEffect(() => {
- if (selectedWorkItems) {
- setSelectedIssues(selectedWorkItems);
+ if (selectedWorkItemIds) {
+ setSelectedIssues(issues.filter((issue) => selectedWorkItemIds.includes(issue.id)));
}
- }, [isOpen, selectedWorkItems]);
+ }, [isOpen, selectedWorkItemIds]);
useEffect(() => {
handleSearch();
diff --git a/apps/web/core/components/project/settings/features-list.tsx b/apps/web/core/components/project/settings/features-list.tsx
index c919b7c9e..8024def86 100644
--- a/apps/web/core/components/project/settings/features-list.tsx
+++ b/apps/web/core/components/project/settings/features-list.tsx
@@ -3,12 +3,11 @@
import type { FC } from "react";
import { observer } from "mobx-react";
// plane imports
-import { PROJECT_TRACKER_ELEMENTS, PROJECT_TRACKER_EVENTS } from "@plane/constants";
+import { PROJECT_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { setPromiseToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { IProject } from "@plane/types";
-import { ToggleSwitch } from "@plane/ui";
// components
import { SettingsHeading } from "@/components/settings/heading";
// helpers
@@ -19,6 +18,7 @@ import { useUser } from "@/hooks/store/user";
// plane web imports
import { UpgradeBadge } from "@/plane-web/components/workspace/upgrade-badge";
import { PROJECT_FEATURES_LIST } from "@/plane-web/constants/project/settings";
+import { ProjectFeatureToggle } from "./helper";
type Props = {
workspaceSlug: string;
@@ -96,12 +96,13 @@ export const ProjectFeaturesList: FC = observer((props) => {
- handleSubmit(featureItemKey, featureItem.property)}
- disabled={!featureItem.isEnabled || !isAdmin}
- size="sm"
- data-ph-element={PROJECT_TRACKER_ELEMENTS.TOGGLE_FEATURE}
+ handleSubmit={handleSubmit}
+ disabled={!isAdmin}
/>
diff --git a/apps/web/core/components/project/settings/helper.tsx b/apps/web/core/components/project/settings/helper.tsx
new file mode 100644
index 000000000..0b7b18432
--- /dev/null
+++ b/apps/web/core/components/project/settings/helper.tsx
@@ -0,0 +1,41 @@
+import Link from "next/link";
+import { ChevronRight } from "lucide-react";
+import { PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
+import { EPillVariant, Pill, EPillSize } from "@plane/propel/pill";
+import { ToggleSwitch } from "@plane/ui";
+import type { TProperties } from "@/plane-web/constants/project/settings/features";
+
+type Props = {
+ workspaceSlug: string;
+ projectId: string;
+ featureItem: TProperties;
+ value: boolean;
+ handleSubmit: (featureKey: string, featureProperty: string) => void;
+ disabled?: boolean;
+};
+
+export const ProjectFeatureToggle = (props: Props) => {
+ const { workspaceSlug, projectId, featureItem, value, handleSubmit, disabled } = props;
+ return featureItem.href ? (
+
+
+
+ {value ? "Enabled" : "Disabled"}
+
+
+
+
+ ) : (
+
handleSubmit(featureItem.key, featureItem.property)}
+ disabled={disabled}
+ size="sm"
+ data-ph-element={PROJECT_TRACKER_ELEMENTS.TOGGLE_FEATURE}
+ />
+ );
+};
diff --git a/apps/web/core/components/sidebar/add-button.tsx b/apps/web/core/components/sidebar/add-button.tsx
index 7634e508d..cea37334f 100644
--- a/apps/web/core/components/sidebar/add-button.tsx
+++ b/apps/web/core/components/sidebar/add-button.tsx
@@ -1,5 +1,5 @@
-import React from "react";
import type { FC } from "react";
+import React from "react";
import { cn } from "@plane/utils";
type Props = React.ComponentProps<"button"> & {
diff --git a/apps/web/core/components/sidebar/search-button.tsx b/apps/web/core/components/sidebar/search-button.tsx
index cf8614905..d87adf84b 100644
--- a/apps/web/core/components/sidebar/search-button.tsx
+++ b/apps/web/core/components/sidebar/search-button.tsx
@@ -1,5 +1,5 @@
-import React from "react";
import type { FC } from "react";
+import React from "react";
import { Search } from "lucide-react";
import { cn } from "@plane/utils";
diff --git a/apps/web/core/store/project/project.store.ts b/apps/web/core/store/project/project.store.ts
index fa99f77f1..1f4cd0802 100644
--- a/apps/web/core/store/project/project.store.ts
+++ b/apps/web/core/store/project/project.store.ts
@@ -12,7 +12,7 @@ import { ProjectService, ProjectStateService, ProjectArchiveService } from "@/se
// store
import type { CoreRootStore } from "../root.store";
-type ProjectOverviewCollapsible = "links" | "attachments";
+type ProjectOverviewCollapsible = "links" | "attachments" | "milestones";
export interface IProjectStore {
// observables
diff --git a/apps/web/ee/components/projects/settings/features-list.tsx b/apps/web/ee/components/projects/settings/features-list.tsx
new file mode 100644
index 000000000..26fc591fd
--- /dev/null
+++ b/apps/web/ee/components/projects/settings/features-list.tsx
@@ -0,0 +1 @@
+export { ProjectFeaturesList } from "@/components/project/settings/features-list";