From c31a225775723dfdd2530ac07e471b3578179d36 Mon Sep 17 00:00:00 2001 From: Sangeetha Date: Thu, 27 Nov 2025 18:12:20 +0530 Subject: [PATCH] [WEB-5506] fix: new navigation pre release bugs (#8181) * chore: update navigation_project_limit and navigation_control_preference * chore: set default true for user specific widgets * chore: use serializer in ProjectMemberPreferenceEndpoint chore: use serializer in WorkspaceUserPropertiesEndpoint " * fix: validate preferences * fix: status code * fix: remove saving from validate * fix: simply validate_preferences * chore: create WorkspaceUserProperties if it doesn't exist * fix: create WorksapceUserProperties it not exist * fix: copy the instance * Revert "fix: copy the instance" This reverts commit ddb0384b6dfa0dc52929972c4e2cd7ce85c69667. * chore: migrate WorkspaceUserPreference to set defaults * fix: migration file name * Revert "fix: migration file name" This reverts commit 80a21dedf1a1245f22e45bfeaf20e8e9f91a1cbf. * Revert "chore: migrate WorkspaceUserPreference to set defaults" This reverts commit 25bc583a081ce79d52ec721f69cf8e61de3e8fb3. --- apps/api/plane/app/serializers/__init__.py | 1 + apps/api/plane/app/serializers/project.py | 12 +++++++++ apps/api/plane/app/views/project/member.py | 26 ++++++++----------- apps/api/plane/app/views/workspace/user.py | 23 +++++++++------- .../app/views/workspace/user_preference.py | 10 +++++++ 5 files changed, 47 insertions(+), 25 deletions(-) diff --git a/apps/api/plane/app/serializers/__init__.py b/apps/api/plane/app/serializers/__init__.py index 18be363cd..759f27ed6 100644 --- a/apps/api/plane/app/serializers/__init__.py +++ b/apps/api/plane/app/serializers/__init__.py @@ -37,6 +37,7 @@ from .project import ( ProjectMemberAdminSerializer, ProjectPublicMemberSerializer, ProjectMemberRoleSerializer, + ProjectMemberPreferenceSerializer, ) from .state import StateSerializer, StateLiteSerializer from .view import IssueViewSerializer, ViewIssueListSerializer diff --git a/apps/api/plane/app/serializers/project.py b/apps/api/plane/app/serializers/project.py index c709093ad..01569cbc9 100644 --- a/apps/api/plane/app/serializers/project.py +++ b/apps/api/plane/app/serializers/project.py @@ -142,6 +142,18 @@ class ProjectMemberSerializer(BaseSerializer): fields = "__all__" +class ProjectMemberPreferenceSerializer(BaseSerializer): + class Meta: + model = ProjectMember + fields = ["preferences", "project_id", "member_id", "workspace_id"] + + def validate_preferences(self, value): + preferences = self.instance.preferences + + preferences.update(value) + return preferences + + class ProjectMemberAdminSerializer(BaseSerializer): workspace = WorkspaceLiteSerializer(read_only=True) project = ProjectLiteSerializer(read_only=True) diff --git a/apps/api/plane/app/views/project/member.py b/apps/api/plane/app/views/project/member.py index 241b56221..69d45226c 100644 --- a/apps/api/plane/app/views/project/member.py +++ b/apps/api/plane/app/views/project/member.py @@ -8,6 +8,7 @@ from plane.app.serializers import ( ProjectMemberSerializer, ProjectMemberAdminSerializer, ProjectMemberRoleSerializer, + ProjectMemberPreferenceSerializer, ) from plane.app.permissions import WorkspaceUserPermission @@ -303,7 +304,7 @@ class UserProjectRolesEndpoint(BaseAPIView): class ProjectMemberPreferenceEndpoint(BaseAPIView): - def get_project_member(self, slug, project_id, member_id): + def get_queryset(self, slug, project_id, member_id): return ProjectMember.objects.get( project_id=project_id, member_id=member_id, @@ -312,25 +313,20 @@ class ProjectMemberPreferenceEndpoint(BaseAPIView): @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) def patch(self, request, slug, project_id, member_id): - project_member = self.get_project_member(slug, project_id, member_id) + project_member = self.get_queryset(slug, project_id, member_id) - current_preferences = project_member.preferences or {} - current_preferences["navigation"] = request.data["navigation"] + serializer = ProjectMemberPreferenceSerializer(project_member, {"preferences": request.data}, partial=True) - project_member.preferences = current_preferences - project_member.save(update_fields=["preferences"]) + if serializer.is_valid(): + serializer.save() - return Response({"preferences": project_member.preferences}, status=status.HTTP_200_OK) + return Response({"preferences": serializer.data["preferences"]}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) def get(self, request, slug, project_id, member_id): - project_member = self.get_project_member(slug, project_id, member_id) + project_member = self.get_queryset(slug, project_id, member_id) - response = { - "preferences": project_member.preferences, - "project_id": project_member.project_id, - "member_id": project_member.member_id, - "workspace_id": project_member.workspace_id, - } + serializer = ProjectMemberPreferenceSerializer(project_member) - return Response(response, status=status.HTTP_200_OK) + return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/apps/api/plane/app/views/workspace/user.py b/apps/api/plane/app/views/workspace/user.py index 0d4f152ee..b45c6e410 100644 --- a/apps/api/plane/app/views/workspace/user.py +++ b/apps/api/plane/app/views/workspace/user.py @@ -249,23 +249,26 @@ class WorkspaceUserPropertiesEndpoint(BaseAPIView): permission_classes = [WorkspaceViewerPermission] def patch(self, request, slug): - workspace_properties = WorkspaceUserProperties.objects.get(user=request.user, workspace__slug=slug) + workspace = Workspace.objects.get(slug=slug) - workspace_properties.filters = request.data.get("filters", workspace_properties.filters) - workspace_properties.rich_filters = request.data.get("rich_filters", workspace_properties.rich_filters) - workspace_properties.display_filters = request.data.get("display_filters", workspace_properties.display_filters) - workspace_properties.display_properties = request.data.get( - "display_properties", workspace_properties.display_properties + (workspace_properties, _) = WorkspaceUserProperties.objects.get_or_create( + user=request.user, workspace_id=workspace.id ) - workspace_properties.save() - serializer = WorkspaceUserPropertiesSerializer(workspace_properties) - return Response(serializer.data, status=status.HTTP_201_CREATED) + serializer = WorkspaceUserPropertiesSerializer(workspace_properties, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def get(self, request, slug): + workspace = Workspace.objects.get(slug=slug) + (workspace_properties, _) = WorkspaceUserProperties.objects.get_or_create( - user=request.user, workspace__slug=slug + user=request.user, workspace=workspace ) + serializer = WorkspaceUserPropertiesSerializer(workspace_properties) return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/apps/api/plane/app/views/workspace/user_preference.py b/apps/api/plane/app/views/workspace/user_preference.py index 3b8edd8ca..253f715b3 100644 --- a/apps/api/plane/app/views/workspace/user_preference.py +++ b/apps/api/plane/app/views/workspace/user_preference.py @@ -39,6 +39,16 @@ class WorkspaceUserPreferenceViewSet(BaseAPIView): user=request.user, workspace=workspace, sort_order=(65535 + (i * 10000)), + is_pinned=( + True + if key + in [ + WorkspaceUserPreference.UserPreferenceKeys.DRAFTS, + WorkspaceUserPreference.UserPreferenceKeys.YOUR_WORK, + WorkspaceUserPreference.UserPreferenceKeys.STICKIES, + ] + else False + ), ) for i, key in enumerate(create_preference_keys) ],