feat: cycles and modules issues state group percentages (#484)

* dev: state group issue percentage on cycle list

* dev: add issue percentage fields for modules and query updates on cycle apis
This commit is contained in:
pablohashescobar 2023-03-22 01:36:52 +05:30 committed by GitHub
parent 5e81600e38
commit c4594bff01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 245 additions and 33 deletions

View File

@ -11,6 +11,12 @@ from plane.db.models import Cycle, CycleIssue, CycleFavorite
class CycleSerializer(BaseSerializer): class CycleSerializer(BaseSerializer):
owned_by = UserLiteSerializer(read_only=True) owned_by = UserLiteSerializer(read_only=True)
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
completed_issues = serializers.IntegerField(read_only=True)
started_issues = serializers.IntegerField(read_only=True)
unstarted_issues = serializers.IntegerField(read_only=True)
backlog_issues = serializers.IntegerField(read_only=True)
class Meta: class Meta:
model = Cycle model = Cycle

View File

@ -133,9 +133,14 @@ class ModuleSerializer(BaseSerializer):
project_detail = ProjectSerializer(read_only=True, source="project") project_detail = ProjectSerializer(read_only=True, source="project")
lead_detail = UserLiteSerializer(read_only=True, source="lead") lead_detail = UserLiteSerializer(read_only=True, source="lead")
members_detail = UserLiteSerializer(read_only=True, many=True, source="members") members_detail = UserLiteSerializer(read_only=True, many=True, source="members")
issue_module = ModuleIssueSerializer(read_only=True, many=True)
link_module = ModuleLinkSerializer(read_only=True, many=True) link_module = ModuleLinkSerializer(read_only=True, many=True)
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
completed_issues = serializers.IntegerField(read_only=True)
started_issues = serializers.IntegerField(read_only=True)
unstarted_issues = serializers.IntegerField(read_only=True)
backlog_issues = serializers.IntegerField(read_only=True)
class Meta: class Meta:
model = Module model = Module

View File

@ -3,7 +3,7 @@ import json
# Django imports # Django imports
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models import OuterRef, Func, F, Q, Exists, OuterRef, Prefetch from django.db.models import OuterRef, Func, F, Q, Exists, OuterRef, Count, Prefetch
from django.core import serializers from django.core import serializers
from django.utils import timezone from django.utils import timezone
@ -64,6 +64,37 @@ class CycleViewSet(BaseViewSet):
.select_related("workspace") .select_related("workspace")
.select_related("owned_by") .select_related("owned_by")
.annotate(is_favorite=Exists(subquery)) .annotate(is_favorite=Exists(subquery))
.annotate(total_issues=Count("issue_cycle"))
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="backlog"),
)
)
.distinct() .distinct()
) )
@ -336,18 +367,92 @@ class CurrentUpcomingCyclesEndpoint(BaseAPIView):
project_id=project_id, project_id=project_id,
workspace__slug=slug, workspace__slug=slug,
) )
current_cycle = Cycle.objects.filter( current_cycle = (
workspace__slug=slug, Cycle.objects.filter(
project_id=project_id, workspace__slug=slug,
start_date__lte=timezone.now(), project_id=project_id,
end_date__gte=timezone.now(), start_date__lte=timezone.now(),
).annotate(is_favorite=Exists(subquery)) end_date__gte=timezone.now(),
)
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.annotate(total_issues=Count("issue_cycle"))
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="backlog"),
)
)
)
upcoming_cycle = Cycle.objects.filter( upcoming_cycle = (
workspace__slug=slug, Cycle.objects.filter(
project_id=project_id, workspace__slug=slug,
start_date__gt=timezone.now(), project_id=project_id,
).annotate(is_favorite=Exists(subquery)) start_date__gt=timezone.now(),
)
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.annotate(total_issues=Count("issue_cycle"))
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="backlog"),
)
)
)
return Response( return Response(
{ {
@ -378,11 +483,48 @@ class CompletedCyclesEndpoint(BaseAPIView):
project_id=project_id, project_id=project_id,
workspace__slug=slug, workspace__slug=slug,
) )
completed_cycles = Cycle.objects.filter( completed_cycles = (
workspace__slug=slug, Cycle.objects.filter(
project_id=project_id, workspace__slug=slug,
end_date__lt=timezone.now(), project_id=project_id,
).annotate(is_favorite=Exists(subquery)) end_date__lt=timezone.now(),
)
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.annotate(total_issues=Count("issue_cycle"))
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="backlog"),
)
)
)
return Response( return Response(
{ {
@ -408,11 +550,47 @@ class DraftCyclesEndpoint(BaseAPIView):
def get(self, request, slug, project_id): def get(self, request, slug, project_id):
try: try:
draft_cycles = Cycle.objects.filter( draft_cycles = (
workspace__slug=slug, Cycle.objects.filter(
project_id=project_id, workspace__slug=slug,
end_date=None, project_id=project_id,
start_date=None, end_date=None,
start_date=None,
)
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(total_issues=Count("issue_cycle"))
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(issue_cycle__issue__state__group="backlog"),
)
)
) )
return Response( return Response(

View File

@ -3,7 +3,7 @@ import json
# Django Imports # Django Imports
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models import Prefetch, F, OuterRef, Func, Exists from django.db.models import Prefetch, F, OuterRef, Func, Exists, Count, Q
from django.core import serializers from django.core import serializers
# Third party imports # Third party imports
@ -65,20 +65,43 @@ class ModuleViewSet(BaseViewSet):
.select_related("workspace") .select_related("workspace")
.select_related("lead") .select_related("lead")
.prefetch_related("members") .prefetch_related("members")
.prefetch_related(
Prefetch(
"issue_module",
queryset=ModuleIssue.objects.select_related(
"module", "issue", "issue__state", "issue__project"
).prefetch_related("issue__assignees", "issue__labels"),
)
)
.prefetch_related( .prefetch_related(
Prefetch( Prefetch(
"link_module", "link_module",
queryset=ModuleLink.objects.select_related("module", "created_by"), queryset=ModuleLink.objects.select_related("module", "created_by"),
) )
) )
.annotate(total_issues=Count("issue_module"))
.annotate(
completed_issues=Count(
"issue_module__issue__state__group",
filter=Q(issue_module__issue__state__group="completed"),
)
)
.annotate(
cancelled_issues=Count(
"issue_module__issue__state__group",
filter=Q(issue_module__issue__state__group="cancelled"),
)
)
.annotate(
started_issues=Count(
"issue_module__issue__state__group",
filter=Q(issue_module__issue__state__group="started"),
)
)
.annotate(
unstarted_issues=Count(
"issue_module__issue__state__group",
filter=Q(issue_module__issue__state__group="unstarted"),
)
)
.annotate(
backlog_issues=Count(
"issue_module__issue__state__group",
filter=Q(issue_module__issue__state__group="backlog"),
)
)
) )
def create(self, request, slug, project_id): def create(self, request, slug, project_id):