feat: user project sorting (#1719)

* feat: user project sorting

* dev: migration typo fix and query member fix

* feat: project member sort order update

* fix: project sorting per members
This commit is contained in:
Nikhil 2023-07-31 18:12:02 +05:30 committed by GitHub
parent 40fd7790eb
commit cc2e6182b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 12 deletions

View File

@ -93,6 +93,7 @@ class ProjectDetailSerializer(BaseSerializer):
total_cycles = serializers.IntegerField(read_only=True)
total_modules = serializers.IntegerField(read_only=True)
is_member = serializers.BooleanField(read_only=True)
sort_order = serializers.FloatField(read_only=True)
class Meta:
model = Project

View File

@ -5,7 +5,7 @@ from datetime import datetime
# Django imports
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.db.models import Q, Exists, OuterRef, Func, F
from django.db.models import Q, Exists, OuterRef, Func, F, Min, Subquery
from django.core.validators import validate_email
from django.conf import settings
@ -120,9 +120,15 @@ class ProjectViewSet(BaseViewSet):
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
)
sort_order_query = ProjectMember.objects.filter(
member=request.user,
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
).values("sort_order")
projects = (
self.get_queryset()
.annotate(is_favorite=Exists(subquery))
.annotate(sort_order=Subquery(sort_order_query))
.order_by("sort_order", "name")
.annotate(
total_members=ProjectMember.objects.filter(
@ -592,17 +598,26 @@ class AddMemberToProjectEndpoint(BaseAPIView):
{"error": "Atleast one member is required"},
status=status.HTTP_400_BAD_REQUEST,
)
bulk_project_members = []
project_members = ProjectMember.objects.bulk_create(
[
project_members = ProjectMember.objects.filter(
workspace=self.workspace, member_id__in=[member.get("member_id") for member in members]
).values("member_id").annotate(sort_order_min=Min("sort_order"))
for member in members:
sort_order = [project_member.get("sort_order") for project_member in project_members]
bulk_project_members.append(
ProjectMember(
member_id=member.get("member_id"),
role=member.get("role", 10),
project_id=project_id,
workspace_id=project.workspace_id,
sort_order=sort_order[0] - 10000 if len(sort_order) else 65535
)
for member in members
],
)
project_members = ProjectMember.objects.bulk_create(
bulk_project_members,
batch_size=10,
ignore_conflicts=True,
)
@ -845,12 +860,14 @@ class ProjectUserViewsEndpoint(BaseAPIView):
view_props = project_member.view_props
default_props = project_member.default_props
preferences = project_member.preferences
sort_order = project_member.sort_order
project_member.view_props = request.data.get("view_props", view_props)
project_member.default_props = request.data.get(
"default_props", default_props
)
project_member.preferences = request.data.get("preferences", preferences)
project_member.sort_order = request.data.get("sort_order", sort_order)
project_member.save()

View File

@ -58,16 +58,16 @@ def update_workspace_member_props(apps, schema_editor):
Model.objects.bulk_update(updated_workspace_member, ["view_props"], batch_size=100)
def update_project_sort_order(apps, schema_editor):
Model = apps.get_model("db", "Project")
def update_project_member_sort_order(apps, schema_editor):
Model = apps.get_model("db", "ProjectMember")
updated_projects = []
updated_project_members = []
for obj in Model.objects.all():
obj.sort_order = random.randint(1, 65536)
updated_projects.append(obj)
updated_project_members.append(obj)
Model.objects.bulk_update(updated_projects, ["sort_order"], batch_size=100)
Model.objects.bulk_update(updated_project_members, ["sort_order"], batch_size=100)
class Migration(migrations.Migration):
@ -93,5 +93,5 @@ class Migration(migrations.Migration):
name='sort_order',
field=models.FloatField(default=65535),
),
migrations.RunPython(update_project_sort_order),
migrations.RunPython(update_project_member_sort_order),
]

View File

@ -91,7 +91,6 @@ class Project(BaseModel):
default_state = models.ForeignKey(
"db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
)
sort_order = models.FloatField(default=65535)
def __str__(self):
"""Return name of the project"""
@ -156,6 +155,20 @@ class ProjectMember(ProjectBaseModel):
view_props = models.JSONField(default=get_default_props)
default_props = models.JSONField(default=get_default_props)
preferences = models.JSONField(default=get_default_preferences)
sort_order = models.FloatField(default=65535)
def save(self, *args, **kwargs):
if self._state.adding:
smallest_sort_order = ProjectMember.objects.filter(
workspace=self.workspace, member=self.member
).aggregate(smallest=models.Min("sort_order"))["smallest"]
# Project ordering
if smallest_sort_order is not None:
self.sort_order = smallest_sort_order - 10000
super(ProjectMember, self).save(*args, **kwargs)
class Meta:
unique_together = ["project", "member"]