[WEB-1989] chore: archived modules and cycles (#5212)
* chore: added estimates in module, cycle endpoint * fix fetching of cycles and modules from appropriate endpoints * chore: added archived at in the cycle detail --------- Co-authored-by: rahulramesha <rahulramesham@gmail.com>
This commit is contained in:
parent
3c684ecab7
commit
8415df4cf3
6 changed files with 398 additions and 54 deletions
|
|
@ -14,21 +14,18 @@ from django.db.models import (
|
||||||
UUIDField,
|
UUIDField,
|
||||||
Value,
|
Value,
|
||||||
When,
|
When,
|
||||||
|
Subquery,
|
||||||
|
Sum,
|
||||||
|
FloatField,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce, Cast
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
# Third party imports
|
# Third party imports
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from plane.app.permissions import ProjectEntityPermission
|
from plane.app.permissions import ProjectEntityPermission
|
||||||
from plane.db.models import (
|
from plane.db.models import Cycle, UserFavorite, Issue, Label, User, Project
|
||||||
Cycle,
|
|
||||||
UserFavorite,
|
|
||||||
Issue,
|
|
||||||
Label,
|
|
||||||
User,
|
|
||||||
)
|
|
||||||
from plane.utils.analytics_plot import burndown_plot
|
from plane.utils.analytics_plot import burndown_plot
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
|
|
@ -49,6 +46,89 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
project_id=self.kwargs.get("project_id"),
|
project_id=self.kwargs.get("project_id"),
|
||||||
workspace__slug=self.kwargs.get("slug"),
|
workspace__slug=self.kwargs.get("slug"),
|
||||||
)
|
)
|
||||||
|
backlog_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="backlog",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
backlog_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("backlog_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
unstarted_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="unstarted",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
unstarted_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("unstarted_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
started_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="started",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
started_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("started_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
cancelled_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="cancelled",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
cancelled_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("cancelled_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
completed_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="completed",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
completed_estimate_points=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("completed_estimate_points")[:1]
|
||||||
|
)
|
||||||
|
total_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
issue_cycle__cycle_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_cycle__cycle_id")
|
||||||
|
.annotate(
|
||||||
|
total_estimate_points=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("total_estimate_points")[:1]
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
Cycle.objects.filter(workspace__slug=self.kwargs.get("slug"))
|
Cycle.objects.filter(workspace__slug=self.kwargs.get("slug"))
|
||||||
.filter(project_id=self.kwargs.get("project_id"))
|
.filter(project_id=self.kwargs.get("project_id"))
|
||||||
|
|
@ -172,6 +252,42 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
Value([], output_field=ArrayField(UUIDField())),
|
Value([], output_field=ArrayField(UUIDField())),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.annotate(
|
||||||
|
backlog_estimate_points=Coalesce(
|
||||||
|
Subquery(backlog_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
unstarted_estimate_points=Coalesce(
|
||||||
|
Subquery(unstarted_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
started_estimate_points=Coalesce(
|
||||||
|
Subquery(started_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
cancelled_estimate_points=Coalesce(
|
||||||
|
Subquery(cancelled_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
completed_estimate_points=Coalesce(
|
||||||
|
Subquery(completed_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
total_estimate_points=Coalesce(
|
||||||
|
Subquery(total_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
.order_by("-is_favorite", "name")
|
.order_by("-is_favorite", "name")
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
@ -179,17 +295,7 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
def get(self, request, slug, project_id, pk=None):
|
def get(self, request, slug, project_id, pk=None):
|
||||||
if pk is None:
|
if pk is None:
|
||||||
queryset = (
|
queryset = (
|
||||||
self.get_queryset()
|
self.get_queryset().values(
|
||||||
.annotate(
|
|
||||||
total_issues=Count(
|
|
||||||
"issue_cycle",
|
|
||||||
filter=Q(
|
|
||||||
issue_cycle__issue__archived_at__isnull=True,
|
|
||||||
issue_cycle__issue__is_draft=False,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.values(
|
|
||||||
# necessary fields
|
# necessary fields
|
||||||
"id",
|
"id",
|
||||||
"workspace_id",
|
"workspace_id",
|
||||||
|
|
@ -255,7 +361,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
"external_id",
|
"external_id",
|
||||||
"progress_snapshot",
|
"progress_snapshot",
|
||||||
"sub_issues",
|
"sub_issues",
|
||||||
|
"logo_props",
|
||||||
# meta fields
|
# meta fields
|
||||||
|
"completed_estimate_points",
|
||||||
|
"total_estimate_points",
|
||||||
"is_favorite",
|
"is_favorite",
|
||||||
"total_issues",
|
"total_issues",
|
||||||
"cancelled_issues",
|
"cancelled_issues",
|
||||||
|
|
@ -265,15 +374,112 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
"backlog_issues",
|
"backlog_issues",
|
||||||
"assignee_ids",
|
"assignee_ids",
|
||||||
"status",
|
"status",
|
||||||
|
"created_by",
|
||||||
|
"archived_at",
|
||||||
)
|
)
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
queryset = queryset.first()
|
queryset = queryset.first()
|
||||||
|
|
||||||
if data is None:
|
estimate_type = Project.objects.filter(
|
||||||
return Response(
|
workspace__slug=slug,
|
||||||
{"error": "Cycle does not exist"},
|
pk=project_id,
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
estimate__isnull=False,
|
||||||
|
estimate__type="points",
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
data["estimate_distribution"] = {}
|
||||||
|
if estimate_type:
|
||||||
|
assignee_distribution = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
issue_cycle__cycle_id=pk,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
.annotate(display_name=F("assignees__display_name"))
|
||||||
|
.annotate(assignee_id=F("assignees__id"))
|
||||||
|
.annotate(avatar=F("assignees__avatar"))
|
||||||
|
.values("display_name", "assignee_id", "avatar")
|
||||||
|
.annotate(
|
||||||
|
total_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
completed_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField()),
|
||||||
|
filter=Q(
|
||||||
|
completed_at__isnull=False,
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
pending_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField()),
|
||||||
|
filter=Q(
|
||||||
|
completed_at__isnull=True,
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.order_by("display_name")
|
||||||
|
)
|
||||||
|
|
||||||
|
label_distribution = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
issue_cycle__cycle_id=pk,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
)
|
||||||
|
.annotate(label_name=F("labels__name"))
|
||||||
|
.annotate(color=F("labels__color"))
|
||||||
|
.annotate(label_id=F("labels__id"))
|
||||||
|
.values("label_name", "color", "label_id")
|
||||||
|
.annotate(
|
||||||
|
total_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
completed_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField()),
|
||||||
|
filter=Q(
|
||||||
|
completed_at__isnull=False,
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
pending_estimates=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField()),
|
||||||
|
filter=Q(
|
||||||
|
completed_at__isnull=True,
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.order_by("label_name")
|
||||||
|
)
|
||||||
|
data["estimate_distribution"] = {
|
||||||
|
"assignees": assignee_distribution,
|
||||||
|
"labels": label_distribution,
|
||||||
|
"completion_chart": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if data["start_date"] and data["end_date"]:
|
||||||
|
data["estimate_distribution"]["completion_chart"] = (
|
||||||
|
burndown_plot(
|
||||||
|
queryset=queryset,
|
||||||
|
slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
plot_type="points",
|
||||||
|
cycle_id=pk,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Assignee Distribution
|
# Assignee Distribution
|
||||||
|
|
@ -298,7 +504,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
.annotate(
|
.annotate(
|
||||||
total_issues=Count(
|
total_issues=Count(
|
||||||
"id",
|
"id",
|
||||||
filter=Q(archived_at__isnull=True, is_draft=False),
|
filter=Q(
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
|
|
@ -338,7 +547,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
.annotate(
|
.annotate(
|
||||||
total_issues=Count(
|
total_issues=Count(
|
||||||
"id",
|
"id",
|
||||||
filter=Q(archived_at__isnull=True, is_draft=False),
|
filter=Q(
|
||||||
|
archived_at__isnull=True,
|
||||||
|
is_draft=False,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
data[0]["estimate_distribution"] = {}
|
data[0]["estimate_distribution"] = {}
|
||||||
if estimate_type:
|
if estimate_type:
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=data[0]["id"],
|
issue_cycle__cycle_id=data[0]["id"],
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -423,7 +423,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
label_distribution = (
|
label_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=data[0]["id"],
|
issue_cycle__cycle_id=data[0]["id"],
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -477,7 +477,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=data[0]["id"],
|
issue_cycle__cycle_id=data[0]["id"],
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -519,7 +519,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
label_distribution = (
|
label_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=data[0]["id"],
|
issue_cycle__cycle_id=data[0]["id"],
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -834,7 +834,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
data["estimate_distribution"] = {}
|
data["estimate_distribution"] = {}
|
||||||
if estimate_type:
|
if estimate_type:
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=pk,
|
issue_cycle__cycle_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -872,7 +872,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
label_distribution = (
|
label_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=pk,
|
issue_cycle__cycle_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -927,7 +927,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
|
|
||||||
# Assignee Distribution
|
# Assignee Distribution
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=pk,
|
issue_cycle__cycle_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -978,7 +978,7 @@ class CycleViewSet(BaseViewSet):
|
||||||
|
|
||||||
# Label Distribution
|
# Label Distribution
|
||||||
label_distribution = (
|
label_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_cycle__cycle_id=pk,
|
issue_cycle__cycle_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ from django.db.models import (
|
||||||
Subquery,
|
Subquery,
|
||||||
UUIDField,
|
UUIDField,
|
||||||
Value,
|
Value,
|
||||||
Sum
|
Sum,
|
||||||
|
FloatField,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import Coalesce, Cast
|
from django.db.models.functions import Coalesce, Cast
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
@ -44,8 +45,8 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
favorite_subquery = UserFavorite.objects.filter(
|
favorite_subquery = UserFavorite.objects.filter(
|
||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
entity_identifier=OuterRef("pk"),
|
|
||||||
entity_type="module",
|
entity_type="module",
|
||||||
|
entity_identifier=OuterRef("pk"),
|
||||||
project_id=self.kwargs.get("project_id"),
|
project_id=self.kwargs.get("project_id"),
|
||||||
workspace__slug=self.kwargs.get("slug"),
|
workspace__slug=self.kwargs.get("slug"),
|
||||||
)
|
)
|
||||||
|
|
@ -102,8 +103,93 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
.annotate(cnt=Count("pk"))
|
.annotate(cnt=Count("pk"))
|
||||||
.values("cnt")
|
.values("cnt")
|
||||||
)
|
)
|
||||||
|
completed_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="completed",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
completed_estimate_points=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("completed_estimate_points")[:1]
|
||||||
|
)
|
||||||
|
|
||||||
|
total_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
total_estimate_points=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("total_estimate_points")[:1]
|
||||||
|
)
|
||||||
|
backlog_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="backlog",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
backlog_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("backlog_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
unstarted_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="unstarted",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
unstarted_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("unstarted_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
started_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="started",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
started_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("started_estimate_point")[:1]
|
||||||
|
)
|
||||||
|
cancelled_estimate_point = (
|
||||||
|
Issue.issue_objects.filter(
|
||||||
|
estimate_point__estimate__type="points",
|
||||||
|
state__group="cancelled",
|
||||||
|
issue_module__module_id=OuterRef("pk"),
|
||||||
|
)
|
||||||
|
.values("issue_module__module_id")
|
||||||
|
.annotate(
|
||||||
|
cancelled_estimate_point=Sum(
|
||||||
|
Cast("estimate_point__value", FloatField())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.values("cancelled_estimate_point")[:1]
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
Module.objects.filter(workspace__slug=self.kwargs.get("slug"))
|
Module.objects.filter(workspace__slug=self.kwargs.get("slug"))
|
||||||
|
.filter(project_id=self.kwargs.get("project_id"))
|
||||||
.filter(archived_at__isnull=False)
|
.filter(archived_at__isnull=False)
|
||||||
.annotate(is_favorite=Exists(favorite_subquery))
|
.annotate(is_favorite=Exists(favorite_subquery))
|
||||||
.select_related("workspace", "project", "lead")
|
.select_related("workspace", "project", "lead")
|
||||||
|
|
@ -152,6 +238,42 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
Value(0, output_field=IntegerField()),
|
Value(0, output_field=IntegerField()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.annotate(
|
||||||
|
backlog_estimate_points=Coalesce(
|
||||||
|
Subquery(backlog_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
unstarted_estimate_points=Coalesce(
|
||||||
|
Subquery(unstarted_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
started_estimate_points=Coalesce(
|
||||||
|
Subquery(started_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
cancelled_estimate_points=Coalesce(
|
||||||
|
Subquery(cancelled_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
completed_estimate_points=Coalesce(
|
||||||
|
Subquery(completed_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
total_estimate_points=Coalesce(
|
||||||
|
Subquery(total_estimate_point),
|
||||||
|
Value(0, output_field=FloatField()),
|
||||||
|
),
|
||||||
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
member_ids=Coalesce(
|
member_ids=Coalesce(
|
||||||
ArrayAgg(
|
ArrayAgg(
|
||||||
|
|
@ -232,7 +354,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
data["estimate_distribution"] = {}
|
data["estimate_distribution"] = {}
|
||||||
|
|
||||||
if estimate_type:
|
if estimate_type:
|
||||||
label_distribution = (
|
assignee_distribution = (
|
||||||
Issue.issue_objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_module__module_id=pk,
|
issue_module__module_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
|
|
@ -252,12 +374,12 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
total_estimates=Sum(
|
total_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField())
|
Cast("estimate_point__value", FloatField())
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
completed_estimates=Sum(
|
completed_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField()),
|
Cast("estimate_point__value", FloatField()),
|
||||||
filter=Q(
|
filter=Q(
|
||||||
completed_at__isnull=False,
|
completed_at__isnull=False,
|
||||||
archived_at__isnull=True,
|
archived_at__isnull=True,
|
||||||
|
|
@ -267,7 +389,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
pending_estimates=Sum(
|
pending_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField()),
|
Cast("estimate_point__value", FloatField()),
|
||||||
filter=Q(
|
filter=Q(
|
||||||
completed_at__isnull=True,
|
completed_at__isnull=True,
|
||||||
archived_at__isnull=True,
|
archived_at__isnull=True,
|
||||||
|
|
@ -278,7 +400,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
.order_by("first_name", "last_name")
|
.order_by("first_name", "last_name")
|
||||||
)
|
)
|
||||||
|
|
||||||
assignee_distribution = (
|
label_distribution = (
|
||||||
Issue.issue_objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_module__module_id=pk,
|
issue_module__module_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
|
|
@ -290,12 +412,12 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
.values("label_name", "color", "label_id")
|
.values("label_name", "color", "label_id")
|
||||||
.annotate(
|
.annotate(
|
||||||
total_estimates=Sum(
|
total_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField())
|
Cast("estimate_point__value", FloatField())
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
completed_estimates=Sum(
|
completed_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField()),
|
Cast("estimate_point__value", FloatField()),
|
||||||
filter=Q(
|
filter=Q(
|
||||||
completed_at__isnull=False,
|
completed_at__isnull=False,
|
||||||
archived_at__isnull=True,
|
archived_at__isnull=True,
|
||||||
|
|
@ -305,7 +427,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
pending_estimates=Sum(
|
pending_estimates=Sum(
|
||||||
Cast("estimate_point__value", IntegerField()),
|
Cast("estimate_point__value", FloatField()),
|
||||||
filter=Q(
|
filter=Q(
|
||||||
completed_at__isnull=True,
|
completed_at__isnull=True,
|
||||||
archived_at__isnull=True,
|
archived_at__isnull=True,
|
||||||
|
|
@ -315,8 +437,8 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
)
|
)
|
||||||
.order_by("label_name")
|
.order_by("label_name")
|
||||||
)
|
)
|
||||||
data["estimate_distribution"]["assignee"] = assignee_distribution
|
data["estimate_distribution"]["assignees"] = assignee_distribution
|
||||||
data["estimate_distribution"]["label"] = label_distribution
|
data["estimate_distribution"]["labels"] = label_distribution
|
||||||
|
|
||||||
if modules and modules.start_date and modules.target_date:
|
if modules and modules.start_date and modules.target_date:
|
||||||
data["estimate_distribution"]["completion_chart"] = (
|
data["estimate_distribution"]["completion_chart"] = (
|
||||||
|
|
@ -328,6 +450,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
module_id=pk,
|
module_id=pk,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.issue_objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_module__module_id=pk,
|
issue_module__module_id=pk,
|
||||||
|
|
@ -353,7 +476,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
archived_at__isnull=True,
|
archived_at__isnull=True,
|
||||||
is_draft=False,
|
is_draft=False,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
completed_issues=Count(
|
completed_issues=Count(
|
||||||
|
|
@ -425,8 +548,6 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
|
||||||
"labels": label_distribution,
|
"labels": label_distribution,
|
||||||
"completion_chart": {},
|
"completion_chart": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fetch the modules
|
|
||||||
if modules and modules.start_date and modules.target_date:
|
if modules and modules.start_date and modules.target_date:
|
||||||
data["distribution"]["completion_chart"] = burndown_plot(
|
data["distribution"]["completion_chart"] = burndown_plot(
|
||||||
queryset=modules,
|
queryset=modules,
|
||||||
|
|
|
||||||
|
|
@ -555,7 +555,7 @@ class ModuleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
assignee_distribution = (
|
assignee_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_module__module_id=pk,
|
issue_module__module_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
@ -605,7 +605,7 @@ class ModuleViewSet(BaseViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
label_distribution = (
|
label_distribution = (
|
||||||
Issue.objects.filter(
|
Issue.issue_objects.filter(
|
||||||
issue_module__module_id=pk,
|
issue_module__module_id=pk,
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
|
||||||
const peekCycle = searchParams.get("peekCycle") || undefined;
|
const peekCycle = searchParams.get("peekCycle") || undefined;
|
||||||
// hooks
|
// hooks
|
||||||
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
|
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
|
||||||
const { getPlotTypeByCycleId, setPlotType, getCycleById, fetchCycleDetails } = useCycle();
|
const { getPlotTypeByCycleId, setPlotType, getCycleById, fetchCycleDetails, fetchArchivedCycleDetails } = useCycle();
|
||||||
const {
|
const {
|
||||||
issuesFilter: { issueFilters, updateFilters },
|
issuesFilter: { issueFilters, updateFilters },
|
||||||
} = useIssues(EIssuesStoreType.CYCLE);
|
} = useIssues(EIssuesStoreType.CYCLE);
|
||||||
|
|
@ -108,6 +108,7 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
|
||||||
const isCycleStartDateValid = cycleStartDate && cycleStartDate <= new Date();
|
const isCycleStartDateValid = cycleStartDate && cycleStartDate <= new Date();
|
||||||
const isCycleEndDateValid = cycleStartDate && cycleEndDate && cycleEndDate >= cycleStartDate;
|
const isCycleEndDateValid = cycleStartDate && cycleEndDate && cycleEndDate >= cycleStartDate;
|
||||||
const isCycleDateValid = isCycleStartDateValid && isCycleEndDateValid;
|
const isCycleDateValid = isCycleStartDateValid && isCycleEndDateValid;
|
||||||
|
const isArchived = !!cycleDetails?.archived_at;
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
const onChange = async (value: TCyclePlotType) => {
|
const onChange = async (value: TCyclePlotType) => {
|
||||||
|
|
@ -115,7 +116,11 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
|
||||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||||
try {
|
try {
|
||||||
setLoader(true);
|
setLoader(true);
|
||||||
|
if (isArchived) {
|
||||||
|
await fetchArchivedCycleDetails(workspaceSlug, projectId, cycleId);
|
||||||
|
} else {
|
||||||
await fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
await fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
||||||
|
}
|
||||||
setLoader(false);
|
setLoader(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoader(false);
|
setLoader(false);
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ export const ModuleAnalyticsProgress: FC<TModuleAnalyticsProgress> = observer((p
|
||||||
const peekModule = searchParams.get("peekModule") || undefined;
|
const peekModule = searchParams.get("peekModule") || undefined;
|
||||||
// hooks
|
// hooks
|
||||||
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
|
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
|
||||||
const { getPlotTypeByModuleId, setPlotType, getModuleById, fetchModuleDetails } = useModule();
|
const { getPlotTypeByModuleId, setPlotType, getModuleById, fetchModuleDetails, fetchArchivedModuleDetails } =
|
||||||
|
useModule();
|
||||||
const {
|
const {
|
||||||
issuesFilter: { issueFilters, updateFilters },
|
issuesFilter: { issueFilters, updateFilters },
|
||||||
} = useIssues(EIssuesStoreType.MODULE);
|
} = useIssues(EIssuesStoreType.MODULE);
|
||||||
|
|
@ -92,6 +93,7 @@ export const ModuleAnalyticsProgress: FC<TModuleAnalyticsProgress> = observer((p
|
||||||
const isModuleStartDateValid = moduleStartDate && moduleStartDate <= new Date();
|
const isModuleStartDateValid = moduleStartDate && moduleStartDate <= new Date();
|
||||||
const isModuleEndDateValid = moduleStartDate && moduleEndDate && moduleEndDate >= moduleStartDate;
|
const isModuleEndDateValid = moduleStartDate && moduleEndDate && moduleEndDate >= moduleStartDate;
|
||||||
const isModuleDateValid = isModuleStartDateValid && isModuleEndDateValid;
|
const isModuleDateValid = isModuleStartDateValid && isModuleEndDateValid;
|
||||||
|
const isArchived = !!moduleDetails?.archived_at;
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
const onChange = async (value: TModulePlotType) => {
|
const onChange = async (value: TModulePlotType) => {
|
||||||
|
|
@ -99,7 +101,11 @@ export const ModuleAnalyticsProgress: FC<TModuleAnalyticsProgress> = observer((p
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
try {
|
try {
|
||||||
setLoader(true);
|
setLoader(true);
|
||||||
|
if (isArchived) {
|
||||||
|
await fetchArchivedModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
} else {
|
||||||
await fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
await fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
}
|
||||||
setLoader(false);
|
setLoader(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoader(false);
|
setLoader(false);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue