diff --git a/apiserver/plane/app/serializers/project.py b/apiserver/plane/app/serializers/project.py index 0cf9c86793f..73c8a85d973 100644 --- a/apiserver/plane/app/serializers/project.py +++ b/apiserver/plane/app/serializers/project.py @@ -91,7 +91,6 @@ class Meta: class ProjectListSerializer(DynamicBaseSerializer): is_favorite = serializers.BooleanField(read_only=True) - is_member = serializers.BooleanField(read_only=True) sort_order = serializers.FloatField(read_only=True) member_role = serializers.IntegerField(read_only=True) anchor = serializers.CharField(read_only=True) @@ -120,7 +119,6 @@ class ProjectDetailSerializer(BaseSerializer): default_assignee = UserLiteSerializer(read_only=True) project_lead = UserLiteSerializer(read_only=True) is_favorite = serializers.BooleanField(read_only=True) - is_member = serializers.BooleanField(read_only=True) sort_order = serializers.FloatField(read_only=True) member_role = serializers.IntegerField(read_only=True) anchor = serializers.CharField(read_only=True) diff --git a/apiserver/plane/app/views/project/base.py b/apiserver/plane/app/views/project/base.py index d92922d0357..2b9d65e10f7 100644 --- a/apiserver/plane/app/views/project/base.py +++ b/apiserver/plane/app/views/project/base.py @@ -70,16 +70,6 @@ def get_queryset(self): ) ) ) - .annotate( - is_member=Exists( - ProjectMember.objects.filter( - member=self.request.user, - project_id=OuterRef("pk"), - workspace__slug=self.kwargs.get("slug"), - is_active=True, - ) - ) - ) .annotate( member_role=ProjectMember.objects.filter( project_id=OuterRef("pk"), @@ -164,14 +154,11 @@ def list(self, request, slug): "workspace", "workspace__owner", "default_assignee", "project_lead" ) .annotate( - is_member=Exists( - ProjectMember.objects.filter( - member=self.request.user, - project_id=OuterRef("pk"), - workspace__slug=self.kwargs.get("slug"), - is_active=True, - ) - ) + member_role=ProjectMember.objects.filter( + project_id=OuterRef("pk"), + member_id=self.request.user.id, + is_active=True, + ).values("role") ) .annotate(inbox_view=F("intake_view")) .annotate(sort_order=Subquery(sort_order)) @@ -182,7 +169,7 @@ def list(self, request, slug): "identifier", "sort_order", "logo_props", - "is_member", + "member_role", "archived_at", "workspace", "cycle_view", diff --git a/packages/types/src/project/projects.d.ts b/packages/types/src/project/projects.d.ts index 269e1477a59..035762ab715 100644 --- a/packages/types/src/project/projects.d.ts +++ b/packages/types/src/project/projects.d.ts @@ -16,7 +16,7 @@ export interface IPartialProject { identifier: string; sort_order: number | null; logo_props: TLogoProps; - is_member: boolean; + member_role: TUserPermissions | null; archived_at: string | null; workspace: IWorkspace | string; cycle_view: boolean; @@ -50,7 +50,6 @@ export interface IProject extends IPartialProject { is_favorite?: boolean; is_issue_type_enabled?: boolean; is_time_tracking_enabled?: boolean; - member_role?: TUserPermissions | null; members?: string[]; network?: number; timezone?: string; diff --git a/web/ce/components/projects/page.tsx b/web/ce/components/projects/page.tsx index a44ab7df40c..8e15ebff79c 100644 --- a/web/ce/components/projects/page.tsx +++ b/web/ce/components/projects/page.tsx @@ -1,3 +1,25 @@ +"use client"; + +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import useSWR from "swr"; +// components import Root from "@/components/project/root"; +// hooks +import { useProject, useWorkspace } from "@/hooks/store"; + +export const ProjectPageRoot = observer(() => { + // router + const { workspaceSlug } = useParams(); + // store + const { currentWorkspace } = useWorkspace(); + const { fetchProjects } = useProject(); + // fetching workspace projects + useSWR( + workspaceSlug && currentWorkspace ? `WORKSPACE_PROJECTS_${workspaceSlug}` : null, + workspaceSlug && currentWorkspace ? () => fetchProjects(workspaceSlug.toString()) : null, + { revalidateIfStale: false, revalidateOnFocus: false } + ); -export const ProjectPageRoot = () => ; + return ; +}); diff --git a/web/core/components/project/card.tsx b/web/core/components/project/card.tsx index 341ddcf8f0a..ae7e1310794 100644 --- a/web/core/components/project/card.tsx +++ b/web/core/components/project/card.tsx @@ -63,8 +63,9 @@ export const ProjectCard: React.FC = observer((props) => { EUserPermissionsLevel.WORKSPACE ); // auth - const isOwner = project.member_role === EUserPermissions.ADMIN; - const isMember = project.member_role === EUserPermissions.MEMBER; + const isMemberOfProject = !!project.member_role; + const hasAdminRole = project.member_role === EUserPermissions.ADMIN; + const hasMemberRole = project.member_role === EUserPermissions.MEMBER; // archive const isArchived = !!project.archived_at; @@ -119,21 +120,21 @@ export const ProjectCard: React.FC = observer((props) => { action: () => router.push(`/${workspaceSlug}/projects/${project.id}/settings`, {}, { showProgressBar: false }), title: "Settings", icon: Settings, - shouldRender: !isArchived && (isOwner || isMember), + shouldRender: !isArchived && (hasAdminRole || hasMemberRole), }, { key: "join", action: () => setJoinProjectModal(true), title: "Join", icon: UserPlus, - shouldRender: !project.is_member && !isArchived, + shouldRender: !isMemberOfProject && !isArchived, }, { key: "open-new-tab", action: handleOpenInNewTab, title: "Open in new tab", icon: ExternalLink, - shouldRender: project.is_member && !isArchived, + shouldRender: !isMemberOfProject && !isArchived, }, { key: "copy-link", @@ -147,14 +148,14 @@ export const ProjectCard: React.FC = observer((props) => { action: () => setRestoreProject(true), title: "Restore", icon: ArchiveRestoreIcon, - shouldRender: isArchived && isOwner, + shouldRender: isArchived && hasAdminRole, }, { key: "delete", action: () => setDeleteProjectModal(true), title: "Delete", icon: Trash2, - shouldRender: isArchived && isOwner, + shouldRender: isArchived && hasAdminRole, }, ]; @@ -189,13 +190,13 @@ export const ProjectCard: React.FC = observer((props) => { ref={projectCardRef} href={`/${workspaceSlug}/projects/${project.id}/issues`} onClick={(e) => { - if (!project.is_member || isArchived) { + if (!isMemberOfProject || isArchived) { e.preventDefault(); e.stopPropagation(); if (!isArchived) setJoinProjectModal(true); } }} - data-prevent-nprogress={!project.is_member || isArchived} + data-prevent-nprogress={!isMemberOfProject || isArchived} className="flex flex-col rounded border border-custom-border-200 bg-custom-background-100" > @@ -297,7 +298,7 @@ export const ProjectCard: React.FC = observer((props) => { {isArchived &&
Archived
} {isArchived ? ( - isOwner && ( + hasAdminRole && (
= observer((props) => { ) ) : ( <> - {project.is_member && - (isOwner || isMember ? ( + {isMemberOfProject && + (hasAdminRole || hasMemberRole ? ( { @@ -343,7 +344,7 @@ export const ProjectCard: React.FC = observer((props) => { Joined ))} - {!project.is_member && ( + {!isMemberOfProject && (