diff --git a/.github/workflows/repo-sync.yml b/.github/workflows/repo-sync.yml index 665a7dbe2e..9ac4771ef6 100644 --- a/.github/workflows/repo-sync.yml +++ b/.github/workflows/repo-sync.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: branches: - - develop + - preview env: SOURCE_BRANCH_NAME: ${{ github.ref_name }} diff --git a/apiserver/plane/app/serializers/view.py b/apiserver/plane/app/serializers/view.py index 32fba7d0c9..6b08ae80b8 100644 --- a/apiserver/plane/app/serializers/view.py +++ b/apiserver/plane/app/serializers/view.py @@ -3,18 +3,12 @@ from rest_framework import serializers # Module imports from .base import DynamicBaseSerializer -from .workspace import WorkspaceLiteSerializer -from .project import ProjectLiteSerializer from plane.db.models import IssueView from plane.utils.issue_filters import issue_filters class IssueViewSerializer(DynamicBaseSerializer): is_favorite = serializers.BooleanField(read_only=True) - project_detail = ProjectLiteSerializer(source="project", read_only=True) - workspace_detail = WorkspaceLiteSerializer( - source="workspace", read_only=True - ) class Meta: model = IssueView @@ -24,6 +18,8 @@ class IssueViewSerializer(DynamicBaseSerializer): "project", "query", "owned_by", + "access", + "is_locked", ] def create(self, validated_data): diff --git a/apiserver/plane/app/views/view/base.py b/apiserver/plane/app/views/view/base.py index 8e9f5b284a..fc44866fc2 100644 --- a/apiserver/plane/app/views/view/base.py +++ b/apiserver/plane/app/views/view/base.py @@ -69,11 +69,40 @@ class WorkspaceViewViewSet(BaseViewSet): .get_queryset() .filter(workspace__slug=self.kwargs.get("slug")) .filter(project__isnull=True) + .filter(Q(owned_by=self.request.user) | Q(access=1)) .select_related("workspace") .order_by(self.request.GET.get("order_by", "-created_at")) .distinct() ) + def partial_update(self, request, slug, pk): + workspace_view = IssueView.objects.get( + pk=pk, + workspace__slug=slug, + ) + + if workspace_view.is_locked: + return Response( + {"error": "view is locked"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + # Only update the view if owner is updating + if workspace_view.owned_by_id != request.user.id: + return Response( + {"error": "Only the owner of the view can update the view"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + serializer = IssueViewSerializer( + workspace_view, 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) + class WorkspaceViewIssuesViewSet(BaseViewSet): permission_classes = [ @@ -294,6 +323,7 @@ class IssueViewViewSet(BaseViewSet): project__project_projectmember__is_active=True, project__archived_at__isnull=True, ) + .filter(Q(owned_by=self.request.user) | Q(access=1)) .select_related("project") .select_related("workspace") .annotate(is_favorite=Exists(subquery)) @@ -313,6 +343,33 @@ class IssueViewViewSet(BaseViewSet): ).data return Response(views, status=status.HTTP_200_OK) + def partial_update(self, request, slug, project_id, pk): + issue_view = IssueView.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + + if issue_view.is_locked: + return Response( + {"error": "view is locked"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + # Only update the view if owner is updating + if issue_view.owned_by_id != request.user.id: + return Response( + {"error": "Only the owner of the view can update the view"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + serializer = IssueViewSerializer( + issue_view, 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) + class IssueViewFavoriteViewSet(BaseViewSet): model = UserFavorite diff --git a/apiserver/plane/app/views/workspace/cycle.py b/apiserver/plane/app/views/workspace/cycle.py index fa2954d673..f642416e3b 100644 --- a/apiserver/plane/app/views/workspace/cycle.py +++ b/apiserver/plane/app/views/workspace/cycle.py @@ -2,7 +2,6 @@ from django.db.models import ( Q, Count, - Sum, ) # Third party modules @@ -87,29 +86,6 @@ class WorkspaceCyclesEndpoint(BaseAPIView): ), ) ) - .annotate( - total_estimates=Sum("issue_cycle__issue__estimate_point") - ) - .annotate( - completed_estimates=Sum( - "issue_cycle__issue__estimate_point", - filter=Q( - issue_cycle__issue__state__group="completed", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - ) - ) - .annotate( - started_estimates=Sum( - "issue_cycle__issue__estimate_point", - filter=Q( - issue_cycle__issue__state__group="started", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - ) - ) .order_by(self.kwargs.get("order_by", "-created_at")) .distinct() ) diff --git a/packages/ui/src/breadcrumbs/breadcrumbs.tsx b/packages/ui/src/breadcrumbs/breadcrumbs.tsx index 253e8308e0..0318256911 100644 --- a/packages/ui/src/breadcrumbs/breadcrumbs.tsx +++ b/packages/ui/src/breadcrumbs/breadcrumbs.tsx @@ -4,9 +4,10 @@ import { ChevronRight } from "lucide-react"; type BreadcrumbsProps = { children: React.ReactNode; onBack?: () => void; + isLoading?: boolean; }; -const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => { +const Breadcrumbs = ({ children, onBack, isLoading = false }: BreadcrumbsProps) => { const [isSmallScreen, setIsSmallScreen] = React.useState(false); React.useEffect(() => { @@ -21,6 +22,13 @@ const Breadcrumbs = ({ children, onBack }: BreadcrumbsProps) => { const childrenArray = React.Children.toArray(children); + const BreadcrumbItemLoader = ( +