Skip to content

Commit

Permalink
[WEB - 466] perf: improve performance for cycle and module endpoints (#…
Browse files Browse the repository at this point in the history
…3711)

* dev: improve performance for cycle apis

* dev: reduce module endpoints and create a new endpoint for getting issues by list

* dev: remove unwanted fields from module

* dev: update module endpoints

* dev: optimize cycle endpoints

* change module and cycle types

* dev: module optimizations

* dev: fix the issues check

* dev: fix issues endpoint

* dev: update module detail serializer

* modify adding issues to modules and cycles

* dev: update cycle issues

* fix module links

* dev: optimize issue list endpoint

* fix: removing issues from the module when removing module_id from issue peekoverview

* fix: updated the tooltip and ui for cycle select (#3718)

* fix: updated the tooltip and ui for module select (#3716)

---------

Co-authored-by: rahulramesha <[email protected]>
Co-authored-by: gurusainath <[email protected]>
  • Loading branch information
3 people authored Feb 21, 2024
1 parent 92becbc commit ab3c3a6
Show file tree
Hide file tree
Showing 42 changed files with 1,030 additions and 534 deletions.
1 change: 1 addition & 0 deletions apiserver/plane/app/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
)

from .module import (
ModuleDetailSerializer,
ModuleWriteSerializer,
ModuleSerializer,
ModuleIssueSerializer,
Expand Down
82 changes: 35 additions & 47 deletions apiserver/plane/app/serializers/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@

# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from .issue import IssueStateSerializer
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import (
Cycle,
CycleIssue,
CycleFavorite,
CycleUserProperties,
)


class CycleWriteSerializer(BaseSerializer):
def validate(self, data):
if (
Expand All @@ -30,65 +26,57 @@ def validate(self, data):
class Meta:
model = Cycle
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
]


class CycleSerializer(BaseSerializer):
# favorite
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
# state group wise distribution
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)
assignees = serializers.SerializerMethodField(read_only=True)
total_estimates = serializers.IntegerField(read_only=True)
completed_estimates = serializers.IntegerField(read_only=True)
started_estimates = serializers.IntegerField(read_only=True)
workspace_detail = WorkspaceLiteSerializer(
read_only=True, source="workspace"
)
project_detail = ProjectLiteSerializer(read_only=True, source="project")
status = serializers.CharField(read_only=True)

def validate(self, data):
if (
data.get("start_date", None) is not None
and data.get("end_date", None) is not None
and data.get("start_date", None) > data.get("end_date", None)
):
raise serializers.ValidationError(
"Start date cannot exceed end date"
)
return data

def get_assignees(self, obj):
members = [
{
"avatar": assignee.avatar,
"display_name": assignee.display_name,
"id": assignee.id,
}
for issue_cycle in obj.issue_cycle.prefetch_related(
"issue__assignees"
).all()
for assignee in issue_cycle.issue.assignees.all()
]
# Use a set comprehension to return only the unique objects
unique_objects = {frozenset(item.items()) for item in members}

# Convert the set back to a list of dictionaries
unique_list = [dict(item) for item in unique_objects]
# active | draft | upcoming | completed
status = serializers.CharField(read_only=True)

return unique_list

class Meta:
model = Cycle
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
fields = [
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"status",
]
read_only_fields = fields


class CycleIssueSerializer(BaseSerializer):
Expand Down
75 changes: 51 additions & 24 deletions apiserver/plane/app/serializers/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from .base import BaseSerializer, DynamicBaseSerializer
from .user import UserLiteSerializer
from .project import ProjectLiteSerializer
from .workspace import WorkspaceLiteSerializer

from plane.db.models import (
User,
Expand All @@ -19,17 +18,18 @@


class ModuleWriteSerializer(BaseSerializer):
members = serializers.ListField(
lead_id = serializers.PrimaryKeyRelatedField(
source="lead",
queryset=User.objects.all(),
required=False,
allow_null=True,
)
member_ids = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
write_only=True,
required=False,
)

project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(
source="workspace", read_only=True
)

class Meta:
model = Module
fields = "__all__"
Expand All @@ -44,7 +44,9 @@ class Meta:

def to_representation(self, instance):
data = super().to_representation(instance)
data["members"] = [str(member.id) for member in instance.members.all()]
data["member_ids"] = [
str(member.id) for member in instance.members.all()
]
return data

def validate(self, data):
Expand All @@ -59,12 +61,10 @@ def validate(self, data):
return data

def create(self, validated_data):
members = validated_data.pop("members", None)

members = validated_data.pop("member_ids", None)
project = self.context["project"]

module = Module.objects.create(**validated_data, project=project)

if members is not None:
ModuleMember.objects.bulk_create(
[
Expand All @@ -85,7 +85,7 @@ def create(self, validated_data):
return module

def update(self, instance, validated_data):
members = validated_data.pop("members", None)
members = validated_data.pop("member_ids", None)

if members is not None:
ModuleMember.objects.filter(module=instance).delete()
Expand Down Expand Up @@ -142,7 +142,6 @@ class Meta:


class ModuleLinkSerializer(BaseSerializer):
created_by_detail = UserLiteSerializer(read_only=True, source="created_by")

class Meta:
model = ModuleLink
Expand Down Expand Up @@ -170,12 +169,9 @@ def create(self, validated_data):


class ModuleSerializer(DynamicBaseSerializer):
project_detail = ProjectLiteSerializer(read_only=True, source="project")
lead_detail = UserLiteSerializer(read_only=True, source="lead")
members_detail = UserLiteSerializer(
read_only=True, many=True, source="members"
member_ids = serializers.ListField(
child=serializers.UUIDField(), required=False, allow_null=True
)
link_module = ModuleLinkSerializer(read_only=True, many=True)
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
Expand All @@ -186,15 +182,46 @@ class ModuleSerializer(DynamicBaseSerializer):

class Meta:
model = Module
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"created_by",
"updated_by",
fields = [
# Required fields
"id",
"workspace_id",
"project_id",
# Model fields
"name",
"description",
"description_text",
"description_html",
"start_date",
"target_date",
"status",
"lead_id",
"member_ids",
"view_props",
"sort_order",
"external_source",
"external_id",
# computed fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"created_at",
"updated_at",
]
read_only_fields = fields



class ModuleDetailSerializer(ModuleSerializer):

link_module = ModuleLinkSerializer(read_only=True, many=True)

class Meta(ModuleSerializer.Meta):
fields = ModuleSerializer.Meta.fields + ['link_module']


class ModuleFavoriteSerializer(BaseSerializer):
Expand Down
6 changes: 6 additions & 0 deletions apiserver/plane/app/urls/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


from plane.app.views import (
IssueListEndpoint,
IssueViewSet,
LabelViewSet,
BulkCreateIssueLabelsEndpoint,
Expand All @@ -25,6 +26,11 @@


urlpatterns = [
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/list/",
IssueListEndpoint.as_view(),
name="project-issue",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
IssueViewSet.as_view(
Expand Down
1 change: 1 addition & 0 deletions apiserver/plane/app/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
)
from .asset import FileAssetEndpoint, UserAssetsEndpoint, FileAssetViewSet
from .issue import (
IssueListEndpoint,
IssueViewSet,
WorkSpaceIssuesEndpoint,
IssueActivityEndpoint,
Expand Down
Loading

0 comments on commit ab3c3a6

Please sign in to comment.