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_cycles = serializers.IntegerField(read_only=True)
total_modules = serializers.IntegerField(read_only=True) total_modules = serializers.IntegerField(read_only=True)
is_member = serializers.BooleanField(read_only=True) is_member = serializers.BooleanField(read_only=True)
sort_order = serializers.FloatField(read_only=True)
class Meta: class Meta:
model = Project model = Project

View File

@ -5,7 +5,7 @@ from datetime import datetime
# Django imports # Django imports
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import IntegrityError 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.core.validators import validate_email
from django.conf import settings from django.conf import settings
@ -120,9 +120,15 @@ class ProjectViewSet(BaseViewSet):
project_id=OuterRef("pk"), project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"), 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 = ( projects = (
self.get_queryset() self.get_queryset()
.annotate(is_favorite=Exists(subquery)) .annotate(is_favorite=Exists(subquery))
.annotate(sort_order=Subquery(sort_order_query))
.order_by("sort_order", "name") .order_by("sort_order", "name")
.annotate( .annotate(
total_members=ProjectMember.objects.filter( total_members=ProjectMember.objects.filter(
@ -592,17 +598,26 @@ class AddMemberToProjectEndpoint(BaseAPIView):
{"error": "Atleast one member is required"}, {"error": "Atleast one member is required"},
status=status.HTTP_400_BAD_REQUEST, 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( ProjectMember(
member_id=member.get("member_id"), member_id=member.get("member_id"),
role=member.get("role", 10), role=member.get("role", 10),
project_id=project_id, project_id=project_id,
workspace_id=project.workspace_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, batch_size=10,
ignore_conflicts=True, ignore_conflicts=True,
) )
@ -845,12 +860,14 @@ class ProjectUserViewsEndpoint(BaseAPIView):
view_props = project_member.view_props view_props = project_member.view_props
default_props = project_member.default_props default_props = project_member.default_props
preferences = project_member.preferences preferences = project_member.preferences
sort_order = project_member.sort_order
project_member.view_props = request.data.get("view_props", view_props) project_member.view_props = request.data.get("view_props", view_props)
project_member.default_props = request.data.get( project_member.default_props = request.data.get(
"default_props", default_props "default_props", default_props
) )
project_member.preferences = request.data.get("preferences", preferences) project_member.preferences = request.data.get("preferences", preferences)
project_member.sort_order = request.data.get("sort_order", sort_order)
project_member.save() 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) Model.objects.bulk_update(updated_workspace_member, ["view_props"], batch_size=100)
def update_project_sort_order(apps, schema_editor): def update_project_member_sort_order(apps, schema_editor):
Model = apps.get_model("db", "Project") Model = apps.get_model("db", "ProjectMember")
updated_projects = [] updated_project_members = []
for obj in Model.objects.all(): for obj in Model.objects.all():
obj.sort_order = random.randint(1, 65536) 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): class Migration(migrations.Migration):
@ -93,5 +93,5 @@ class Migration(migrations.Migration):
name='sort_order', name='sort_order',
field=models.FloatField(default=65535), 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( default_state = models.ForeignKey(
"db.State", on_delete=models.SET_NULL, null=True, related_name="default_state" "db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
) )
sort_order = models.FloatField(default=65535)
def __str__(self): def __str__(self):
"""Return name of the project""" """Return name of the project"""
@ -156,6 +155,20 @@ class ProjectMember(ProjectBaseModel):
view_props = models.JSONField(default=get_default_props) view_props = models.JSONField(default=get_default_props)
default_props = models.JSONField(default=get_default_props) default_props = models.JSONField(default=get_default_props)
preferences = models.JSONField(default=get_default_preferences) 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: class Meta:
unique_together = ["project", "member"] unique_together = ["project", "member"]