From ee96abd5f2504deb93a9f94dff17c40216a688cd Mon Sep 17 00:00:00 2001 From: Akshita Goyal <36129505+gakshita@users.noreply.github.com> Date: Wed, 18 Jun 2025 20:56:07 +0530 Subject: [PATCH] [WEB-4342] fix: copy to clipboard text + added redirection for pages (#3447) * fix: copy to clipboard text + added redirection for pages * fix: translations * fix: feature flagged * fix: refactor * chore: featureflag check --------- Co-authored-by: sangeethailango --- .../plane/ee/views/app/issue/issue_page.py | 6 ++++ apiserver/plane/payment/flags/flag.py | 2 ++ packages/constants/src/feature-flag.ts | 1 + .../src/locales/en/translations-extended.json | 4 +-- .../issue-detail-widgets/action-buttons.tsx | 33 +++++++++++-------- .../issue-detail-widgets/collapsibles.tsx | 22 ++++++++----- .../issue-detail-widgets/pages/block.tsx | 19 +++++++---- web/ee/hooks/use-issue-properties.tsx | 11 +++++-- 8 files changed, 64 insertions(+), 34 deletions(-) diff --git a/apiserver/plane/ee/views/app/issue/issue_page.py b/apiserver/plane/ee/views/app/issue/issue_page.py index 51fc048631..25f9180757 100644 --- a/apiserver/plane/ee/views/app/issue/issue_page.py +++ b/apiserver/plane/ee/views/app/issue/issue_page.py @@ -11,6 +11,8 @@ from plane.ee.models.issue import WorkItemPage from plane.db.models import Page, Workspace from plane.ee.serializers import WorkItemPageSerializer from plane.app.permissions import ProjectLitePermission +from plane.payment.flags.flag import FeatureFlag +from plane.payment.flags.flag_decorator import check_feature_flag class IssuePageViewSet(BaseAPIView): @@ -21,6 +23,7 @@ class IssuePageViewSet(BaseAPIView): workspace=workspace, project_id=project_id, issue_id=issue_id ) + @check_feature_flag(FeatureFlag.LINK_PAGES) def post(self, request, slug, project_id, issue_id): workspace = Workspace.objects.get(slug=slug) pages_ids = request.data.get("pages_ids", []) @@ -61,12 +64,14 @@ class IssuePageViewSet(BaseAPIView): serializer = WorkItemPageSerializer(work_item_pages, many=True) return Response(serializer.data, status=status.HTTP_201_CREATED) + @check_feature_flag(FeatureFlag.LINK_PAGES) def get(self, request, slug, project_id, issue_id, page_id=None): workspace = Workspace.objects.get(slug=slug) work_item_pages = self.filter_work_item_pages(workspace, project_id, issue_id) serializer = WorkItemPageSerializer(work_item_pages, many=True) return Response(serializer.data, status=status.HTTP_200_OK) + @check_feature_flag(FeatureFlag.LINK_PAGES) def delete(self, request, slug, project_id, issue_id, page_id): workspace = Workspace.objects.get(slug=slug) work_item_page = self.filter_work_item_pages( @@ -79,6 +84,7 @@ class IssuePageViewSet(BaseAPIView): class PageSearchViewSet(BaseAPIView): permission_classes = [ProjectLitePermission] + @check_feature_flag(FeatureFlag.LINK_PAGES) def get(self, request, slug, project_id): is_global = request.query_params.get("is_global", False) search = request.query_params.get("search", "") diff --git a/apiserver/plane/payment/flags/flag.py b/apiserver/plane/payment/flags/flag.py index 8a00a83383..cc6c0a10c6 100644 --- a/apiserver/plane/payment/flags/flag.py +++ b/apiserver/plane/payment/flags/flag.py @@ -78,6 +78,8 @@ class FeatureFlag(Enum): ANALYTICS_ADVANCED = "ANALYTICS_ADVANCED" # Notion Importer NOTION_IMPORTER = "NOTION_IMPORTER" + # Link Pages + LINK_PAGES = "LINK_PAGES" class AdminFeatureFlag(Enum): diff --git a/packages/constants/src/feature-flag.ts b/packages/constants/src/feature-flag.ts index bb12a556df..fd4ab71fbb 100644 --- a/packages/constants/src/feature-flag.ts +++ b/packages/constants/src/feature-flag.ts @@ -39,6 +39,7 @@ export enum E_FEATURE_FLAGS { TIME_ESTIMATES = "TIME_ESTIMATES", PROJECT_TEMPLATES_PUBLISH = "PROJECT_TEMPLATES_PUBLISH", COPY_WORK_ITEM = "COPY_WORK_ITEM", + LINK_PAGES = "LINK_PAGES", // ====== silo importers ====== SILO_IMPORTERS = "SILO_IMPORTERS", diff --git a/packages/i18n/src/locales/en/translations-extended.json b/packages/i18n/src/locales/en/translations-extended.json index be44e8f62f..3f46c772dc 100644 --- a/packages/i18n/src/locales/en/translations-extended.json +++ b/packages/i18n/src/locales/en/translations-extended.json @@ -34,7 +34,7 @@ "duplicate": { "modal": { "title": "Make a copy to another project", - "description1": "This creates a copy of the work item, its attachments, links.", + "description1": "This creates a copy of the work item.", "description2": "All property data will be removed while duplicating.", "placeholder": "Select a project" } @@ -557,7 +557,7 @@ }, "duplicate": { "modal": { - "description1": "This creates a copy of the epic, its attachments, links.", + "description1": "This creates a copy of the epic.", "description2": "All property data will be removed while duplicating.", "epics_not_enabled": "Epics not enabled" } diff --git a/web/ee/components/issues/issue-detail-widgets/action-buttons.tsx b/web/ee/components/issues/issue-detail-widgets/action-buttons.tsx index cb17e4376f..6013d26db8 100644 --- a/web/ee/components/issues/issue-detail-widgets/action-buttons.tsx +++ b/web/ee/components/issues/issue-detail-widgets/action-buttons.tsx @@ -1,28 +1,33 @@ import { FC } from "react"; import { FileText } from "lucide-react"; +import { E_FEATURE_FLAGS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { TWorkItemAdditionalWidgetActionButtonsProps } from "@/ce/components/issues/issue-detail-widgets/action-buttons"; import { IssueDetailWidgetButton } from "@/components/issues"; +import { WithFeatureFlagHOC } from "@/plane-web/components/feature-flags"; import { PagesActionButton } from "./pages"; + export const WorkItemAdditionalWidgetActionButtons: FC = (props) => { const { workspaceSlug, workItemId, disabled, issueServiceType, hideWidgets } = props; const { t } = useTranslation(); return ( <> - {!hideWidgets?.includes("pages") && ( - } - disabled={disabled} - /> - } - /> - )} + }> + {!hideWidgets?.includes("pages") && ( + } + disabled={disabled} + /> + } + /> + )} + ); }; diff --git a/web/ee/components/issues/issue-detail-widgets/collapsibles.tsx b/web/ee/components/issues/issue-detail-widgets/collapsibles.tsx index 481df519b1..a441358cfd 100644 --- a/web/ee/components/issues/issue-detail-widgets/collapsibles.tsx +++ b/web/ee/components/issues/issue-detail-widgets/collapsibles.tsx @@ -1,10 +1,12 @@ import { FC } from "react"; import { observer } from "mobx-react"; // ce imports +import { E_FEATURE_FLAGS } from "@plane/constants"; import { TWorkItemAdditionalWidgetCollapsiblesProps } from "@/ce/components/issues/issue-detail-widgets/collapsibles"; // hooks import { useIssueDetail } from "@/hooks/store"; // plane web imports +import { WithFeatureFlagHOC } from "@/plane-web/components/feature-flags"; import { CustomerRequestsCollapsible } from "@/plane-web/components/issues/issue-detail-widgets"; import { useCustomers } from "@/plane-web/hooks/store"; import { PagesCollapsible } from "./pages"; @@ -27,15 +29,17 @@ export const WorkItemAdditionalWidgetCollapsibles: FC )} - {shouldRenderPages && ( - - )} + }> + {shouldRenderPages && ( + + )} + ); } diff --git a/web/ee/components/issues/issue-detail-widgets/pages/block.tsx b/web/ee/components/issues/issue-detail-widgets/pages/block.tsx index b6977e589e..deb3089d91 100644 --- a/web/ee/components/issues/issue-detail-widgets/pages/block.tsx +++ b/web/ee/components/issues/issue-detail-widgets/pages/block.tsx @@ -1,12 +1,13 @@ import React, { FC } from "react"; import { observer } from "mobx-react"; +import Link from "next/link"; import { CircleX, Files, FileText, Link2 } from "lucide-react"; import { useTranslation } from "@plane/i18n"; import { TIssuePage, TIssueServiceType, TLogoProps } from "@plane/types"; import { setToast, TContextMenuItem, TOAST_TYPE, CustomMenu, Logo } from "@plane/ui"; import { calculateTimeAgo, cn, copyUrlToClipboard } from "@plane/utils"; import { ButtonAvatars } from "@/components/dropdowns/member/avatar"; -import { useIssueDetail, useProject, useWorkspace } from "@/hooks/store"; +import { useIssueDetail, useProject } from "@/hooks/store"; type TProps = { issueServiceType: TIssueServiceType; @@ -21,12 +22,10 @@ export const PagesCollapsibleContentBlock: FC = observer((props) => { // hooks const { t } = useTranslation(); const { getProjectById } = useProject(); - const { getWorkspaceBySlug } = useWorkspace(); const { pages: { deleteIssuePages }, } = useIssueDetail(issueServiceType); // derived - const workspace = getWorkspaceBySlug(workspaceSlug); const project = getProjectById(projectId); const handleCopyText = () => { @@ -36,7 +35,7 @@ export const PagesCollapsibleContentBlock: FC = observer((props) => { setToast({ type: TOAST_TYPE.SUCCESS, title: t("link_copied"), - message: t("project_link_copied_to_clipboard"), + message: t("entity.link_copied_to_clipboard", { entity: t("page") }), }); }); }; @@ -79,7 +78,15 @@ export const PagesCollapsibleContentBlock: FC = observer((props) => { key={page.id} className="flex flex-col gap-2 rounded-xl border border-custom-border-100 p-4 pb-2 min-h-[166px]" > -
+
{page.is_global ? ( @@ -105,7 +112,7 @@ export const PagesCollapsibleContentBlock: FC = observer((props) => { {page.description_stripped === "" ? t("issue.pages.no_description") : page.description_stripped}
-
+
{page.created_by && }
diff --git a/web/ee/hooks/use-issue-properties.tsx b/web/ee/hooks/use-issue-properties.tsx index b28f888514..46a09a052b 100644 --- a/web/ee/hooks/use-issue-properties.tsx +++ b/web/ee/hooks/use-issue-properties.tsx @@ -1,7 +1,9 @@ import useSWR from "swr"; // plane web imports +import { E_FEATURE_FLAGS } from "@plane/constants"; import { TIssueServiceType } from "@plane/types"; import { useIssueDetail } from "@/hooks/store"; +import { useFlag } from "./store/use-flag"; export const useWorkItemProperties = ( projectId: string | null | undefined, workspaceSlug: string | null | undefined, @@ -13,11 +15,14 @@ export const useWorkItemProperties = ( pages: { fetchPagesByIssueId }, } = useIssueDetail(issueServiceType); + const isPagesInWorkitemWidgetEnabled = useFlag(workspaceSlug?.toString(), E_FEATURE_FLAGS.LINK_PAGES); useSWR( - workspaceSlug && projectId && workItemId ? `WORK_ITEM_PAGES_${workspaceSlug}_${projectId}_${workItemId}` : null, - workspaceSlug && projectId && workItemId + workspaceSlug && projectId && workItemId && isPagesInWorkitemWidgetEnabled + ? `WORK_ITEM_PAGES_${workspaceSlug}_${projectId}_${workItemId}_${isPagesInWorkitemWidgetEnabled}` + : null, + workspaceSlug && projectId && workItemId && isPagesInWorkitemWidgetEnabled ? () => fetchPagesByIssueId(workspaceSlug, projectId?.toString() ?? "", workItemId) : null, { revalidateIfStale: false, revalidateOnFocus: true } ); -}; \ No newline at end of file +};