[WEB-2625] chore: workspace favorite and draft improvement (#5855)
* chore: favorite empty state updated * chore: added draft issue count in workspace members * chore: workspace draft count improvement --------- Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
parent
d552913171
commit
a7b58e4a93
6 changed files with 55 additions and 10 deletions
|
|
@ -65,6 +65,7 @@ class WorkSpaceMemberSerializer(DynamicBaseSerializer):
|
||||||
|
|
||||||
|
|
||||||
class WorkspaceMemberMeSerializer(BaseSerializer):
|
class WorkspaceMemberMeSerializer(BaseSerializer):
|
||||||
|
draft_issue_count = serializers.IntegerField(read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WorkspaceMember
|
model = WorkspaceMember
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ from django.db.models import (
|
||||||
CharField,
|
CharField,
|
||||||
Count,
|
Count,
|
||||||
Q,
|
Q,
|
||||||
|
OuterRef,
|
||||||
|
Subquery,
|
||||||
|
IntegerField,
|
||||||
)
|
)
|
||||||
|
from django.db.models.functions import Coalesce
|
||||||
from django.db.models.functions import Cast
|
from django.db.models.functions import Cast
|
||||||
|
|
||||||
# Third party modules
|
# Third party modules
|
||||||
|
|
@ -34,6 +38,7 @@ from plane.db.models import (
|
||||||
User,
|
User,
|
||||||
Workspace,
|
Workspace,
|
||||||
WorkspaceMember,
|
WorkspaceMember,
|
||||||
|
DraftIssue,
|
||||||
)
|
)
|
||||||
from plane.utils.cache import cache_response, invalidate_cache
|
from plane.utils.cache import cache_response, invalidate_cache
|
||||||
|
|
||||||
|
|
@ -283,10 +288,26 @@ class WorkspaceMemberUserViewsEndpoint(BaseAPIView):
|
||||||
|
|
||||||
class WorkspaceMemberUserEndpoint(BaseAPIView):
|
class WorkspaceMemberUserEndpoint(BaseAPIView):
|
||||||
def get(self, request, slug):
|
def get(self, request, slug):
|
||||||
workspace_member = WorkspaceMember.objects.get(
|
draft_issue_count = (
|
||||||
member=request.user,
|
DraftIssue.objects.filter(
|
||||||
workspace__slug=slug,
|
created_by=request.user,
|
||||||
is_active=True,
|
workspace_id=OuterRef("workspace_id"),
|
||||||
|
)
|
||||||
|
.values("workspace_id")
|
||||||
|
.annotate(count=Count("id"))
|
||||||
|
.values("count")
|
||||||
|
)
|
||||||
|
|
||||||
|
workspace_member = (
|
||||||
|
WorkspaceMember.objects.filter(
|
||||||
|
member=request.user, workspace__slug=slug, is_active=True
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
draft_issue_count=Coalesce(
|
||||||
|
Subquery(draft_issue_count, output_field=IntegerField()), 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.first()
|
||||||
)
|
)
|
||||||
serializer = WorkspaceMemberMeSerializer(workspace_member)
|
serializer = WorkspaceMemberMeSerializer(workspace_member)
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
|
||||||
1
packages/types/src/workspace.d.ts
vendored
1
packages/types/src/workspace.d.ts
vendored
|
|
@ -91,6 +91,7 @@ export interface IWorkspaceMemberMe {
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
view_props: IWorkspaceViewProps;
|
view_props: IWorkspaceViewProps;
|
||||||
workspace: string;
|
workspace: string;
|
||||||
|
draft_issue_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILastActiveWorkspaceDetails {
|
export interface ILastActiveWorkspaceDetails {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { FC, useEffect, useRef } from "react";
|
import { FC, useEffect, useRef } from "react";
|
||||||
|
import isEmpty from "lodash/isEmpty";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane helpers
|
// plane helpers
|
||||||
import { useOutsideClickDetector } from "@plane/helpers";
|
import { useOutsideClickDetector } from "@plane/helpers";
|
||||||
|
|
@ -16,8 +17,9 @@ import { SidebarFavoritesMenu } from "@/components/workspace/sidebar/favorites/f
|
||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useAppTheme, useUserPermissions } from "@/hooks/store";
|
import { useAppTheme, useUserPermissions } from "@/hooks/store";
|
||||||
// plane web components
|
import { useFavorite } from "@/hooks/store/use-favorite";
|
||||||
import useSize from "@/hooks/use-window-size";
|
import useSize from "@/hooks/use-window-size";
|
||||||
|
// plane web components
|
||||||
import { SidebarAppSwitcher } from "@/plane-web/components/sidebar";
|
import { SidebarAppSwitcher } from "@/plane-web/components/sidebar";
|
||||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||||
|
|
||||||
|
|
@ -25,6 +27,7 @@ export const AppSidebar: FC = observer(() => {
|
||||||
// store hooks
|
// store hooks
|
||||||
const { allowPermissions } = useUserPermissions();
|
const { allowPermissions } = useUserPermissions();
|
||||||
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
|
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
|
||||||
|
const { groupedFavorites } = useFavorite();
|
||||||
const windowSize = useSize();
|
const windowSize = useSize();
|
||||||
// refs
|
// refs
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
@ -48,6 +51,8 @@ export const AppSidebar: FC = observer(() => {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [windowSize]);
|
}, [windowSize]);
|
||||||
|
|
||||||
|
const isFavoriteEmpty = isEmpty(groupedFavorites);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -91,7 +96,7 @@ export const AppSidebar: FC = observer(() => {
|
||||||
"opacity-0": !sidebarCollapsed,
|
"opacity-0": !sidebarCollapsed,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
{canPerformWorkspaceMemberActions && <SidebarFavoritesMenu />}
|
{canPerformWorkspaceMemberActions && !isFavoriteEmpty && <SidebarFavoritesMenu />}
|
||||||
|
|
||||||
<SidebarProjectsList />
|
<SidebarProjectsList />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export const SidebarUserMenu = observer(() => {
|
||||||
const { captureEvent } = useEventTracker();
|
const { captureEvent } = useEventTracker();
|
||||||
const { isMobile } = usePlatformOS();
|
const { isMobile } = usePlatformOS();
|
||||||
const { data: currentUser } = useUser();
|
const { data: currentUser } = useUser();
|
||||||
const { allowPermissions } = useUserPermissions();
|
const { allowPermissions, workspaceUserInfo } = useUserPermissions();
|
||||||
// router params
|
// router params
|
||||||
const { workspaceSlug } = useParams();
|
const { workspaceSlug } = useParams();
|
||||||
// pathname
|
// pathname
|
||||||
|
|
@ -50,14 +50,17 @@ export const SidebarUserMenu = observer(() => {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const draftIssueCount = workspaceUserInfo[workspaceSlug.toString()]?.draft_issue_count;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn("flex flex-col gap-0.5", {
|
className={cn("flex flex-col gap-0.5", {
|
||||||
"space-y-0": sidebarCollapsed,
|
"space-y-0": sidebarCollapsed,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{SIDEBAR_USER_MENU_ITEMS.map(
|
{SIDEBAR_USER_MENU_ITEMS.map((link) => {
|
||||||
(link) =>
|
if (link.key === "drafts" && draftIssueCount === 0) return null;
|
||||||
|
return (
|
||||||
allowPermissions(link.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString()) && (
|
allowPermissions(link.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString()) && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
key={link.key}
|
key={link.key}
|
||||||
|
|
@ -81,7 +84,8 @@ export const SidebarUserMenu = observer(() => {
|
||||||
</Link>
|
</Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
)}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,13 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateWorkspaceUserDraftIssueCount(workspaceSlug: string, increment: number) {
|
||||||
|
const workspaceUserInfo = this.issueStore.rootStore.user.permission.workspaceUserInfo;
|
||||||
|
const currentCount = workspaceUserInfo[workspaceSlug]?.draft_issue_count ?? 0;
|
||||||
|
|
||||||
|
set(workspaceUserInfo, [workspaceSlug, "draft_issue_count"], currentCount + increment);
|
||||||
|
}
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
get issueIds() {
|
get issueIds() {
|
||||||
const workspaceSlug = this.issueStore.workspaceSlug;
|
const workspaceSlug = this.issueStore.workspaceSlug;
|
||||||
|
|
@ -259,6 +266,8 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues {
|
||||||
total_count: this.paginationInfo.total_count + 1,
|
total_count: this.paginationInfo.total_count + 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Update draft issue count in workspaceUserInfo
|
||||||
|
this.updateWorkspaceUserDraftIssueCount(workspaceSlug, 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,6 +319,8 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues {
|
||||||
total_count: this.paginationInfo.total_count - 1,
|
total_count: this.paginationInfo.total_count - 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Update draft issue count in workspaceUserInfo
|
||||||
|
this.updateWorkspaceUserDraftIssueCount(workspaceSlug, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
|
|
@ -337,6 +348,8 @@ export class WorkspaceDraftIssues implements IWorkspaceDraftIssues {
|
||||||
total_count: this.paginationInfo.total_count - 1,
|
total_count: this.paginationInfo.total_count - 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Update draft issue count in workspaceUserInfo
|
||||||
|
this.updateWorkspaceUserDraftIssueCount(workspaceSlug, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue