Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEB-402] chore: project issues count #3911

Merged
merged 15 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apiserver/plane/app/serializers/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,10 @@ class Meta:

class ModuleDetailSerializer(ModuleSerializer):
link_module = ModuleLinkSerializer(read_only=True, many=True)
sub_issues = serializers.IntegerField(read_only=True)

class Meta(ModuleSerializer.Meta):
fields = ModuleSerializer.Meta.fields + ["link_module"]
fields = ModuleSerializer.Meta.fields + ["link_module", "sub_issues"]


class ModuleFavoriteSerializer(BaseSerializer):
Expand Down
6 changes: 6 additions & 0 deletions apiserver/plane/app/serializers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ class Meta:


class ProjectListSerializer(DynamicBaseSerializer):
total_issues = serializers.IntegerField(read_only=True)
archived_issues = serializers.IntegerField(read_only=True)
archived_sub_issues = serializers.IntegerField(read_only=True)
draft_issues = serializers.IntegerField(read_only=True)
draft_sub_issues = serializers.IntegerField(read_only=True)
sub_issues = serializers.IntegerField(read_only=True)
is_favorite = serializers.BooleanField(read_only=True)
total_members = serializers.IntegerField(read_only=True)
total_cycles = serializers.IntegerField(read_only=True)
Expand Down
62 changes: 41 additions & 21 deletions apiserver/plane/app/views/cycle/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,6 @@ def get_queryset(self):
)
)
.annotate(is_favorite=Exists(favorite_subquery))
.annotate(
total_issues=Count(
"issue_cycle",
filter=Q(
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
Expand Down Expand Up @@ -232,7 +223,6 @@ def list(self, request, slug, project_id):
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand Down Expand Up @@ -327,13 +317,13 @@ def list(self, request, slug, project_id):
}

if data[0]["start_date"] and data[0]["end_date"]:
data[0]["distribution"][
"completion_chart"
] = burndown_plot(
queryset=queryset.first(),
slug=slug,
project_id=project_id,
cycle_id=data[0]["id"],
data[0]["distribution"]["completion_chart"] = (
burndown_plot(
queryset=queryset.first(),
slug=slug,
project_id=project_id,
cycle_id=data[0]["id"],
)
)

return Response(data, status=status.HTTP_200_OK)
Expand All @@ -356,7 +346,6 @@ def list(self, request, slug, project_id):
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand Down Expand Up @@ -402,7 +391,6 @@ def create(self, request, slug, project_id):
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand Down Expand Up @@ -474,7 +462,6 @@ def partial_update(self, request, slug, project_id, pk):
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand All @@ -487,10 +474,42 @@ def partial_update(self, request, slug, project_id, pk):
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def retrieve(self, request, slug, project_id, pk):
queryset = self.get_queryset().filter(pk=pk)
queryset = (
self.get_queryset()
.filter(pk=pk)
.annotate(
total_issues=Count(
"issue_cycle",
filter=Q(
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
)
data = (
self.get_queryset()
.filter(pk=pk)
.annotate(
total_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=True,
issue_cycle__cycle_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
sub_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=False,
issue_cycle__cycle_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.values(
# necessary fields
"id",
Expand All @@ -507,6 +526,7 @@ def retrieve(self, request, slug, project_id, pk):
"external_source",
"external_id",
"progress_snapshot",
"sub_issues",
# meta fields
"is_favorite",
"total_issues",
Expand Down
39 changes: 25 additions & 14 deletions apiserver/plane/app/views/module/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Django Imports
from django.utils import timezone
from django.db.models import Prefetch, F, OuterRef, Exists, Count, Q
from django.db.models import Prefetch, F, OuterRef, Exists, Count, Q, Func
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.fields import ArrayField
from django.db.models import Value, UUIDField
Expand Down Expand Up @@ -79,15 +79,6 @@ def get_queryset(self):
),
)
)
.annotate(
total_issues=Count(
"issue_module",
filter=Q(
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
),
)
.annotate(
completed_issues=Count(
"issue_module__issue__state__group",
Expand Down Expand Up @@ -183,7 +174,6 @@ def create(self, request, slug, project_id):
"external_id",
# computed fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand Down Expand Up @@ -225,7 +215,6 @@ def list(self, request, slug, project_id):
"external_id",
# computed fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand All @@ -237,7 +226,30 @@ def list(self, request, slug, project_id):
return Response(modules, status=status.HTTP_200_OK)

def retrieve(self, request, slug, project_id, pk):
queryset = self.get_queryset().filter(pk=pk)
queryset = (
self.get_queryset()
.filter(pk=pk)
.annotate(
total_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=True,
issue_module__module_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
sub_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=False,
issue_module__module_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)

assignee_distribution = (
Issue.objects.filter(
Expand Down Expand Up @@ -380,7 +392,6 @@ def partial_update(self, request, slug, project_id, pk):
"external_id",
# computed fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
Expand Down
70 changes: 70 additions & 0 deletions apiserver/plane/app/views/project/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
Inbox,
ProjectDeployBoard,
IssueProperty,
Issue,
)
from plane.utils.cache import cache_response


class ProjectViewSet(WebhookMixin, BaseViewSet):
serializer_class = ProjectListSerializer
model = Project
Expand Down Expand Up @@ -171,6 +173,73 @@ def list(self, request, slug):
).data
return Response(projects, status=status.HTTP_200_OK)

def retrieve(self, request, slug, pk):
project = (
self.get_queryset()
.filter(pk=pk)
.annotate(
total_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("pk"),
parent__isnull=True,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
sub_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("pk"),
parent__isnull=False,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
archived_issues=Issue.objects.filter(
project_id=self.kwargs.get("pk"),
archived_at__isnull=False,
parent__isnull=True,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
archived_sub_issues=Issue.objects.filter(
project_id=self.kwargs.get("pk"),
archived_at__isnull=False,
parent__isnull=False,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
draft_issues=Issue.objects.filter(
project_id=self.kwargs.get("pk"),
is_draft=True,
parent__isnull=True,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
draft_sub_issues=Issue.objects.filter(
project_id=self.kwargs.get("pk"),
is_draft=True,
parent__isnull=False,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
).first()

serializer = ProjectListSerializer(project)
return Response(serializer.data, status=status.HTTP_200_OK)

def create(self, request, slug):
try:
workspace = Workspace.objects.get(slug=slug)
Expand Down Expand Up @@ -471,6 +540,7 @@ class ProjectPublicCoverImagesEndpoint(BaseAPIView):
permission_classes = [
AllowAny,
]

# Cache the below api for 24 hours
@cache_response(60 * 60 * 24, user=False)
def get(self, request):
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/cycles.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ICycle {
sort_order: number;
start_date: string | null;
started_issues: number;
sub_issues: number;
total_issues: number;
unstarted_issues: number;
updated_at: Date;
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/modules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface IModule {
name: string;
project_id: string;
sort_order: number;
sub_issues: number;
start_date: string | null;
started_issues: number;
status: TModuleStatus;
Expand Down
6 changes: 6 additions & 0 deletions packages/types/src/projects.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export type TProjectLogoProps = {

export interface IProject {
archive_in: number;
archived_issues: number;
archived_sub_issues: number;
close_in: number;
created_at: Date;
created_by: string;
Expand All @@ -35,6 +37,8 @@ export interface IProject {
default_assignee: IUser | string | null;
default_state: string | null;
description: string;
draft_issues: number;
draft_sub_issues: number;
estimate: string | null;
id: string;
identifier: string;
Expand All @@ -48,7 +52,9 @@ export interface IProject {
network: number;
project_lead: IUserLite | string | null;
sort_order: number | null;
sub_issues: number;
total_cycles: number;
total_issues: number;
total_members: number;
total_modules: number;
updated_at: Date;
Expand Down
17 changes: 13 additions & 4 deletions web/components/headers/cycle-issues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,24 @@ export const CycleIssuesHeader: React.FC = observer(() => {
label={
<>
<ContrastIcon className="h-3 w-3" />
<div className=" w-auto max-w-[70px] sm:max-w-[200px] inline-block truncate line-clamp-1 overflow-hidden whitespace-nowrap">
{cycleDetails?.name && cycleDetails.name}
<div className="flex items-center gap-2 w-auto max-w-[70px] sm:max-w-[200px] truncate">
<p className="truncate">{cycleDetails?.name && cycleDetails.name}</p>
{cycleDetails && issueFilters?.displayFilters && (
<span className="flex items-center text-center justify-center px-2 flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-semibold rounded-xl">
{issueFilters.displayFilters.sub_issue
anmolsinghbhatia marked this conversation as resolved.
Show resolved Hide resolved
? cycleDetails.total_issues + cycleDetails.sub_issues
: cycleDetails.total_issues}
</span>
)}
</div>
</>
}
className="ml-1.5 flex-shrink-0"
className="ml-1.5 flex-shrink-0 truncate"
placement="bottom-start"
>
{currentProjectCycleIds?.map((cycleId) => <CycleDropdownOption key={cycleId} cycleId={cycleId} />)}
{currentProjectCycleIds?.map((cycleId) => (
<CycleDropdownOption key={cycleId} cycleId={cycleId} />
))}
</CustomMenu>
}
/>
Expand Down
Loading
Loading