From ddb07dbe5f38f6b9f2271e05e63f1728fecc5bc6 Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Mon, 8 Apr 2024 19:11:47 +0530 Subject: [PATCH] [WEB-406] chore: project inbox revamp (#4141) * chore: removed inbox id * fix: inbox changes * chore: resolved merge conflicts * chore: inbox issue response changes * chore: inbox issue filters * fix: inbox implementation revamp * fix: type fixes * fix: pagination implementation * fix: inbox fixes * fix: pagination fixes * fix: inbox Issues pagination fixes * chore: triage state change * fix: inbox fixes * chore: filtering using boolean * chore: total results in the pagination * fix: inbox main content changes * fix: develop pull fixes * chore: resolved build erros in inbox issues * dev: fix migrations * chore: module, labels and assignee in inbox * chore: inbox issue order by * chore: inbox filters * chore: inbox ui revamp * chore: inbox type updated * chore: updated filters * chore: updated filter menmbers and date types in inbox issue filter * chore: inbox issue filter updated * chore: updated date filter in the inbox issue filter * chore: moved the current tab state from local state to store * chore: updated the filter and fetch request in the inbox issues * chore: updated tab change handler * chore: handled isEmpty in the issue filters query params * chore: inbox sidebar updated * chore: enabled create inbox issue in mobx * chore: replaced the key inbox_status to status * chore: inbox sidebar pagination * chore: updated inbox issue services * chore: inbox sidebar total count indicator * chore: create inbox issue updated * chore: updated inbox issue sidebar layout * chore: rendering issue detail in inbox issue * chore: inbox issue content updated * chore: create inbox issue modal description improvement * fix: updated delete functionality in inbox store * chore: updated multiple inbox issue creation * chore: handled loading, empty states and inbox user access permissions * chore: updated rendering issues in the sidebar * chore: inbox sidebar label improvement * chore: handled empty states * chore: disabled inbox empty state added * chore: module, labels and assignee in list endpoint * chore: labels in list endpoint * chore: inboc issue serializer * chore: representation in serializer * chore: super function * chore: inbox empty state updated * chore: implemented applied filters * chore: inbox empty state updated * chore: update date formats in applied filters * chore: inbox skeleton updated * chore: ui changes in the siebar list item * chore: removed the module and cycle ids * chore: inbox sidebar tab * chore: inbox actions * chore: updated inbox issue header actions * chore: updated inbox issue code cleanup * chore: loader improvement * chore: inbox sidebar improvement * chore: inbox sidebar empty state flicker * fix: inbox issue delete operation * chore: inbox issue title and description update indicator added * fix: resolved issue property rendering in initial load * chore: inbox sidebar and detail header improvement * fix: handling selected filter in the issue filters and applied filters * chore: inbox issue detail improvement * chore: inbox issue label updated * chore: inbox issue sidebar improvement * fix: handling issue description update when we move between the issues in inbox * chore: removed inbox issue helpers file * chore: boolean checked * chore: resolved file change requests --------- Co-authored-by: NarayanBavisetti Co-authored-by: sriram veeraghanta Co-authored-by: pablohashescobar Co-authored-by: Anmol Singh Bhatia --- apiserver/plane/api/views/inbox.py | 5 +- apiserver/plane/api/views/project.py | 3 +- apiserver/plane/api/views/state.py | 4 +- apiserver/plane/app/serializers/__init__.py | 2 + apiserver/plane/app/serializers/inbox.py | 53 ++- apiserver/plane/app/serializers/issue.py | 22 +- apiserver/plane/app/urls/inbox.py | 4 +- apiserver/plane/app/views/inbox/base.py | 211 +++++----- apiserver/plane/app/views/project/base.py | 3 +- apiserver/plane/app/views/state/base.py | 4 +- .../0063_state_is_triage_alter_state_group.py | 44 +++ apiserver/plane/db/models/issue.py | 4 +- apiserver/plane/db/models/state.py | 2 + apiserver/plane/utils/issue_filters.py | 153 ++++---- apiserver/plane/utils/paginator.py | 3 +- packages/types/src/common.d.ts | 11 + packages/types/src/inbox.d.ts | 76 ++++ packages/types/src/inbox/inbox-issue.d.ts | 65 ---- packages/types/src/inbox/inbox-types.d.ts | 44 --- packages/types/src/inbox/inbox.d.ts | 27 -- packages/types/src/inbox/root.d.ts | 3 - packages/types/src/index.d.ts | 6 +- web/components/headers/project-inbox.tsx | 17 +- .../inbox/content/inbox-issue-header.tsx | 276 +++++++++++++ web/components/inbox/content/index.ts | 4 + .../content/issue-properties.tsx} | 119 +++--- web/components/inbox/content/issue-root.tsx | 174 +++++++++ web/components/inbox/content/root.tsx | 114 +++--- .../inbox-filter/applied-filters/date.tsx | 66 ++++ .../inbox-filter/applied-filters/index.ts | 6 + .../inbox-filter/applied-filters/label.tsx | 55 +++ .../inbox-filter/applied-filters/member.tsx | 59 +++ .../inbox-filter/applied-filters/priority.tsx | 55 +++ .../inbox-filter/applied-filters/root.tsx | 36 ++ .../inbox-filter/applied-filters/status.tsx | 57 +++ .../inbox/inbox-filter/filters/date.tsx | 97 +++++ .../inbox-filter/filters/filter-selection.tsx | 87 +++++ .../inbox/inbox-filter/filters/index.ts | 6 + .../inbox/inbox-filter/filters/labels.tsx | 88 +++++ .../inbox/inbox-filter/filters/members.tsx | 102 +++++ .../inbox/inbox-filter/filters/priority.tsx | 56 +++ .../inbox/inbox-filter/filters/status.tsx | 68 ++++ web/components/inbox/inbox-filter/index.ts | 4 + web/components/inbox/inbox-filter/root.tsx | 18 + .../inbox/inbox-filter/sorting/index.ts | 1 + .../inbox/inbox-filter/sorting/order-by.tsx | 58 +++ web/components/inbox/inbox-issue-actions.tsx | 364 ------------------ web/components/inbox/inbox-issue-status.tsx | 63 ++- web/components/inbox/index.ts | 16 +- .../inbox/modals/accept-issue-modal.tsx | 7 +- .../inbox/modals/create-issue-modal.tsx | 60 ++- .../inbox/modals/decline-issue-modal.tsx | 5 +- .../inbox/modals/delete-issue-modal.tsx | 9 +- web/components/inbox/modals/index.ts | 1 + .../inbox/modals/snooze-issue-modal.tsx | 78 ++++ web/components/inbox/root.tsx | 68 ++++ .../inbox/sidebar/filter/applied-filters.tsx | 171 -------- .../inbox/sidebar/filter/filter-selection.tsx | 117 ------ .../inbox/sidebar/inbox-list-item.tsx | 132 ++++--- web/components/inbox/sidebar/inbox-list.tsx | 48 +-- web/components/inbox/sidebar/index.ts | 3 + web/components/inbox/sidebar/root.tsx | 158 ++++++-- web/components/issues/index.ts | 3 +- .../issues/issue-detail/inbox/index.ts | 3 - .../issue-detail/inbox/main-content.tsx | 119 ------ .../issues/issue-detail/inbox/root.tsx | 152 -------- web/components/issues/issue-detail/index.ts | 14 +- .../issue-detail/label/create-label.tsx | 11 +- .../issue-detail/label/label-list-item.tsx | 13 +- .../issues/issue-detail/label/label-list.tsx | 16 +- .../issues/issue-detail/label/root.tsx | 11 +- .../label/select/label-select.tsx | 13 +- .../issues/issue-detail/label/select/root.tsx | 11 +- web/components/project/sidebar-list-item.tsx | 38 +- .../project-inbox/inbox-layout-loader.tsx | 19 +- .../project-inbox/inbox-sidebar-loader.tsx | 32 +- web/constants/empty-state.ts | 42 ++ web/constants/inbox.tsx | 91 +++-- web/hooks/store/index.ts | 3 +- web/hooks/store/use-inbox-issues.ts | 12 +- web/hooks/store/use-inbox.ts | 11 - web/hooks/store/use-project-inbox.ts | 11 + web/hooks/use-intersection-observer.tsx | 42 ++ web/layouts/auth-layout/project-wrapper.tsx | 20 +- web/next-env.d.ts | 1 - .../projects/[projectId]/inbox/[inboxId].tsx | 80 ---- .../projects/[projectId]/inbox/index.tsx | 57 +-- .../disabled-feature/inbox-dark.webp | Bin 0 -> 60900 bytes .../disabled-feature/inbox-light.webp | Bin 0 -> 63374 bytes .../empty-state/inbox/filter-issue-dark.webp | Bin 0 -> 39760 bytes .../empty-state/inbox/filter-issue-light.webp | Bin 0 -> 40790 bytes .../empty-state/inbox/inbox-issue-dark.webp | Bin 0 -> 40208 bytes .../empty-state/inbox/inbox-issue-light.webp | Bin 0 -> 41402 bytes .../empty-state/inbox/issue-detail-dark.webp | Bin 0 -> 2170 bytes .../empty-state/inbox/issue-detail-light.webp | Bin 0 -> 2264 bytes web/services/inbox.service.ts | 122 ------ web/services/inbox/inbox-issue.service.ts | 108 ++---- web/services/inbox/inbox.service.ts | 35 -- web/services/inbox/index.ts | 1 - web/store/inbox/inbox-issue.store.ts | 139 +++++++ web/store/inbox/inbox.store.ts | 114 ------ web/store/inbox/inbox_filter.store.ts | 129 ------- web/store/inbox/inbox_issue.store.ts | 267 ------------- web/store/inbox/project-inbox.store.ts | 353 +++++++++++++++++ web/store/inbox/root.store.ts | 26 -- web/store/issue/project/filter.store.ts | 4 +- web/store/root.store.ts | 15 +- 107 files changed, 3137 insertions(+), 2673 deletions(-) create mode 100644 apiserver/plane/db/migrations/0063_state_is_triage_alter_state_group.py create mode 100644 packages/types/src/common.d.ts create mode 100644 packages/types/src/inbox.d.ts delete mode 100644 packages/types/src/inbox/inbox-issue.d.ts delete mode 100644 packages/types/src/inbox/inbox-types.d.ts delete mode 100644 packages/types/src/inbox/inbox.d.ts delete mode 100644 packages/types/src/inbox/root.d.ts create mode 100644 web/components/inbox/content/inbox-issue-header.tsx create mode 100644 web/components/inbox/content/index.ts rename web/components/{issues/issue-detail/inbox/sidebar.tsx => inbox/content/issue-properties.tsx} (60%) create mode 100644 web/components/inbox/content/issue-root.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/date.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/index.ts create mode 100644 web/components/inbox/inbox-filter/applied-filters/label.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/member.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/priority.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/root.tsx create mode 100644 web/components/inbox/inbox-filter/applied-filters/status.tsx create mode 100644 web/components/inbox/inbox-filter/filters/date.tsx create mode 100644 web/components/inbox/inbox-filter/filters/filter-selection.tsx create mode 100644 web/components/inbox/inbox-filter/filters/index.ts create mode 100644 web/components/inbox/inbox-filter/filters/labels.tsx create mode 100644 web/components/inbox/inbox-filter/filters/members.tsx create mode 100644 web/components/inbox/inbox-filter/filters/priority.tsx create mode 100644 web/components/inbox/inbox-filter/filters/status.tsx create mode 100644 web/components/inbox/inbox-filter/index.ts create mode 100644 web/components/inbox/inbox-filter/root.tsx create mode 100644 web/components/inbox/inbox-filter/sorting/index.ts create mode 100644 web/components/inbox/inbox-filter/sorting/order-by.tsx delete mode 100644 web/components/inbox/inbox-issue-actions.tsx create mode 100644 web/components/inbox/modals/snooze-issue-modal.tsx create mode 100644 web/components/inbox/root.tsx delete mode 100644 web/components/inbox/sidebar/filter/applied-filters.tsx delete mode 100644 web/components/inbox/sidebar/filter/filter-selection.tsx create mode 100644 web/components/inbox/sidebar/index.ts delete mode 100644 web/components/issues/issue-detail/inbox/index.ts delete mode 100644 web/components/issues/issue-detail/inbox/main-content.tsx delete mode 100644 web/components/issues/issue-detail/inbox/root.tsx delete mode 100644 web/hooks/store/use-inbox.ts create mode 100644 web/hooks/store/use-project-inbox.ts create mode 100644 web/hooks/use-intersection-observer.tsx delete mode 100644 web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx create mode 100644 web/public/empty-state/disabled-feature/inbox-dark.webp create mode 100644 web/public/empty-state/disabled-feature/inbox-light.webp create mode 100644 web/public/empty-state/inbox/filter-issue-dark.webp create mode 100644 web/public/empty-state/inbox/filter-issue-light.webp create mode 100644 web/public/empty-state/inbox/inbox-issue-dark.webp create mode 100644 web/public/empty-state/inbox/inbox-issue-light.webp create mode 100644 web/public/empty-state/inbox/issue-detail-dark.webp create mode 100644 web/public/empty-state/inbox/issue-detail-light.webp delete mode 100644 web/services/inbox.service.ts delete mode 100644 web/services/inbox/inbox.service.ts create mode 100644 web/store/inbox/inbox-issue.store.ts delete mode 100644 web/store/inbox/inbox.store.ts delete mode 100644 web/store/inbox/inbox_filter.store.ts delete mode 100644 web/store/inbox/inbox_issue.store.ts create mode 100644 web/store/inbox/project-inbox.store.ts delete mode 100644 web/store/inbox/root.store.ts diff --git a/apiserver/plane/api/views/inbox.py b/apiserver/plane/api/views/inbox.py index 53248a21a..209b7b658 100644 --- a/apiserver/plane/api/views/inbox.py +++ b/apiserver/plane/api/views/inbox.py @@ -135,10 +135,11 @@ class InboxIssueAPIEndpoint(BaseAPIView): # Create or get state state, _ = State.objects.get_or_create( name="Triage", - group="backlog", + group="triage", description="Default state for managing all Inbox Issues", project_id=project_id, color="#ff7700", + is_triage=True, ) # create an issue @@ -299,7 +300,7 @@ class InboxIssueAPIEndpoint(BaseAPIView): ) # Update the issue state only if it is in triage state - if issue.state.name == "Triage": + if issue.state.is_triage: # Move to default state state = State.objects.filter( workspace__slug=slug, diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 885b7dda5..fcb0cc4fb 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -291,10 +291,11 @@ class ProjectAPIEndpoint(WebhookMixin, BaseAPIView): # Create the triage state in Backlog group State.objects.get_or_create( name="Triage", - group="backlog", + group="triage", description="Default state for managing all Inbox Issues", project_id=pk, color="#ff7700", + is_triage=True, ) project = ( diff --git a/apiserver/plane/api/views/state.py b/apiserver/plane/api/views/state.py index 28181fffb..966c243e3 100644 --- a/apiserver/plane/api/views/state.py +++ b/apiserver/plane/api/views/state.py @@ -29,8 +29,8 @@ class StateAPIEndpoint(BaseAPIView): project__project_projectmember__member=self.request.user, project__project_projectmember__is_active=True, ) + .filter(is_triage=False) .filter(project__archived_at__isnull=True) - .filter(~Q(name="Triage")) .select_related("project") .select_related("workspace") .distinct() @@ -106,7 +106,7 @@ class StateAPIEndpoint(BaseAPIView): def delete(self, request, slug, project_id, state_id): state = State.objects.get( - ~Q(name="Triage"), + is_triage=False, pk=state_id, project_id=project_id, workspace__slug=slug, diff --git a/apiserver/plane/app/serializers/__init__.py b/apiserver/plane/app/serializers/__init__.py index 22673dabc..2f3c94450 100644 --- a/apiserver/plane/app/serializers/__init__.py +++ b/apiserver/plane/app/serializers/__init__.py @@ -59,6 +59,7 @@ from .issue import ( IssueFlatSerializer, IssueStateSerializer, IssueLinkSerializer, + IssueInboxSerializer, IssueLiteSerializer, IssueAttachmentSerializer, IssueSubscriberSerializer, @@ -107,6 +108,7 @@ from .inbox import ( InboxIssueSerializer, IssueStateInboxSerializer, InboxIssueLiteSerializer, + InboxIssueDetailSerializer, ) from .analytic import AnalyticViewSerializer diff --git a/apiserver/plane/app/serializers/inbox.py b/apiserver/plane/app/serializers/inbox.py index 1dc6f1f4a..25b3c8cb3 100644 --- a/apiserver/plane/app/serializers/inbox.py +++ b/apiserver/plane/app/serializers/inbox.py @@ -3,7 +3,11 @@ from rest_framework import serializers # Module imports from .base import BaseSerializer -from .issue import IssueFlatSerializer, LabelLiteSerializer +from .issue import ( + IssueInboxSerializer, + LabelLiteSerializer, + IssueDetailSerializer, +) from .project import ProjectLiteSerializer from .state import StateLiteSerializer from .user import UserLiteSerializer @@ -24,17 +28,58 @@ class InboxSerializer(BaseSerializer): class InboxIssueSerializer(BaseSerializer): - issue_detail = IssueFlatSerializer(source="issue", read_only=True) - project_detail = ProjectLiteSerializer(source="project", read_only=True) + issue = IssueInboxSerializer(read_only=True) class Meta: model = InboxIssue - fields = "__all__" + fields = [ + "id", + "status", + "duplicate_to", + "snoozed_till", + "source", + "issue", + "created_by", + ] read_only_fields = [ "project", "workspace", ] + def to_representation(self, instance): + # Pass the annotated fields to the Issue instance if they exist + if hasattr(instance, "label_ids"): + instance.issue.label_ids = instance.label_ids + return super().to_representation(instance) + + +class InboxIssueDetailSerializer(BaseSerializer): + issue = IssueDetailSerializer(read_only=True) + + class Meta: + model = InboxIssue + fields = [ + "id", + "status", + "duplicate_to", + "snoozed_till", + "source", + "issue", + ] + read_only_fields = [ + "project", + "workspace", + ] + + def to_representation(self, instance): + # Pass the annotated fields to the Issue instance if they exist + if hasattr(instance, "assignee_ids"): + instance.issue.assignee_ids = instance.assignee_ids + if hasattr(instance, "label_ids"): + instance.issue.label_ids = instance.label_ids + + return super().to_representation(instance) + class InboxIssueLiteSerializer(BaseSerializer): class Meta: diff --git a/apiserver/plane/app/serializers/issue.py b/apiserver/plane/app/serializers/issue.py index fc0e6f838..8c641b720 100644 --- a/apiserver/plane/app/serializers/issue.py +++ b/apiserver/plane/app/serializers/issue.py @@ -620,6 +620,26 @@ class IssueStateSerializer(DynamicBaseSerializer): fields = "__all__" +class IssueInboxSerializer(DynamicBaseSerializer): + label_ids = serializers.ListField( + child=serializers.UUIDField(), + required=False, + ) + + class Meta: + model = Issue + fields = [ + "id", + "name", + "priority", + "sequence_id", + "project_id", + "created_at", + "label_ids", + ] + read_only_fields = fields + + class IssueSerializer(DynamicBaseSerializer): # ids cycle_id = serializers.PrimaryKeyRelatedField(read_only=True) @@ -688,7 +708,7 @@ class IssueLiteSerializer(DynamicBaseSerializer): class IssueDetailSerializer(IssueSerializer): description_html = serializers.CharField() - is_subscribed = serializers.BooleanField() + is_subscribed = serializers.BooleanField(read_only=True) class Meta(IssueSerializer.Meta): fields = IssueSerializer.Meta.fields + [ diff --git a/apiserver/plane/app/urls/inbox.py b/apiserver/plane/app/urls/inbox.py index e9ec4e335..b6848244b 100644 --- a/apiserver/plane/app/urls/inbox.py +++ b/apiserver/plane/app/urls/inbox.py @@ -30,7 +30,7 @@ urlpatterns = [ name="inbox", ), path( - "workspaces//projects//inboxes//inbox-issues/", + "workspaces//projects//inbox-issues/", InboxIssueViewSet.as_view( { "get": "list", @@ -40,7 +40,7 @@ urlpatterns = [ name="inbox-issue", ), path( - "workspaces//projects//inboxes//inbox-issues//", + "workspaces//projects//inbox-issues//", InboxIssueViewSet.as_view( { "get": "retrieve", diff --git a/apiserver/plane/app/views/inbox/base.py b/apiserver/plane/app/views/inbox/base.py index 710aa10a2..e486052a3 100644 --- a/apiserver/plane/app/views/inbox/base.py +++ b/apiserver/plane/app/views/inbox/base.py @@ -22,18 +22,17 @@ from plane.db.models import ( InboxIssue, Issue, State, + Workspace, IssueLink, IssueAttachment, ProjectMember, - IssueReaction, - IssueSubscriber, ) from plane.app.serializers import ( IssueCreateSerializer, IssueSerializer, InboxSerializer, InboxIssueSerializer, - IssueDetailSerializer, + InboxIssueDetailSerializer, ) from plane.utils.issue_filters import issue_filters from plane.bgtasks.issue_activites_task import issue_activity @@ -64,13 +63,20 @@ class InboxViewSet(BaseViewSet): .select_related("workspace", "project") ) + def list(self, request, slug, project_id): + inbox = self.get_queryset().first() + return Response( + InboxSerializer(inbox).data, + status=status.HTTP_200_OK, + ) + def perform_create(self, serializer): serializer.save(project_id=self.kwargs.get("project_id")) def destroy(self, request, slug, project_id, pk): - inbox = Inbox.objects.get( + inbox = Inbox.objects.filter( workspace__slug=slug, project_id=project_id, pk=pk - ) + ).first() # Handle default inbox delete if inbox.is_default: return Response( @@ -98,7 +104,6 @@ class InboxIssueViewSet(BaseViewSet): Issue.objects.filter( project_id=self.kwargs.get("project_id"), workspace__slug=self.kwargs.get("slug"), - issue_inbox__inbox_id=self.kwargs.get("inbox_id"), ) .select_related("workspace", "project", "state", "parent") .prefetch_related("assignees", "labels", "issue_module__module") @@ -162,51 +167,50 @@ class InboxIssueViewSet(BaseViewSet): ) ).distinct() - def list(self, request, slug, project_id, inbox_id): - filters = issue_filters(request.query_params, "GET") - issue_queryset = ( - self.get_queryset() - .filter(**filters) - .order_by("issue_inbox__snoozed_till", "issue_inbox__status") - ) - if self.expand: - issues = IssueSerializer( - issue_queryset, expand=self.expand, many=True - ).data - else: - issues = issue_queryset.values( - "id", - "name", - "state_id", - "sort_order", - "completed_at", - "estimate_point", - "priority", - "start_date", - "target_date", - "sequence_id", - "project_id", - "parent_id", - "cycle_id", - "module_ids", - "label_ids", - "assignee_ids", - "sub_issues_count", - "created_at", - "updated_at", - "created_by", - "updated_by", - "attachment_count", - "link_count", - "is_draft", - "archived_at", + def list(self, request, slug, project_id): + workspace = Workspace.objects.filter(slug=slug).first() + inbox_id = Inbox.objects.filter( + workspace_id=workspace.id, project_id=project_id + ).first() + filters = issue_filters(request.GET, "GET", "issue__") + inbox_issue = ( + InboxIssue.objects.filter( + inbox_id=inbox_id.id, project_id=project_id, **filters ) - return Response( - issues, - status=status.HTTP_200_OK, + .select_related("issue") + .prefetch_related( + "issue__labels", + ) + .annotate( + label_ids=Coalesce( + ArrayAgg( + "issue__labels__id", + distinct=True, + filter=~Q(issue__labels__id__isnull=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ) + ) + ).order_by(request.GET.get("order_by", "-issue__created_at")) + # inbox status filter + inbox_status = [ + item + for item in request.GET.get("status", "-2").split(",") + if item != "null" + ] + if inbox_status: + inbox_issue = inbox_issue.filter(status__in=inbox_status) + + return self.paginate( + request=request, + queryset=(inbox_issue), + on_results=lambda inbox_issues: InboxIssueSerializer( + inbox_issues, + many=True, + ).data, ) - def create(self, request, slug, project_id, inbox_id): + def create(self, request, slug, project_id): if not request.data.get("issue", {}).get("name", False): return Response( {"error": "Name is required"}, @@ -229,10 +233,11 @@ class InboxIssueViewSet(BaseViewSet): # Create or get state state, _ = State.objects.get_or_create( name="Triage", - group="backlog", + group="triage", description="Default state for managing all Inbox Issues", project_id=project_id, color="#ff7700", + is_triage=True, ) # create an issue @@ -259,19 +264,25 @@ class InboxIssueViewSet(BaseViewSet): notification=True, origin=request.META.get("HTTP_ORIGIN"), ) + workspace = Workspace.objects.filter(slug=slug).first() + inbox_id = Inbox.objects.filter( + workspace_id=workspace.id, project_id=project_id + ).first() # create an inbox issue - InboxIssue.objects.create( - inbox_id=inbox_id, + inbox_issue = InboxIssue.objects.create( + inbox_id=inbox_id.id, project_id=project_id, issue=issue, source=request.data.get("source", "in-app"), ) - - issue = self.get_queryset().filter(pk=issue.id).first() - serializer = IssueSerializer(issue, expand=self.expand) + serializer = InboxIssueDetailSerializer(inbox_issue) return Response(serializer.data, status=status.HTTP_200_OK) - def partial_update(self, request, slug, project_id, inbox_id, issue_id): + def partial_update(self, request, slug, project_id, issue_id): + workspace = Workspace.objects.filter(slug=slug).first() + inbox_id = Inbox.objects.filter( + workspace_id=workspace.id, project_id=project_id + ).first() inbox_issue = InboxIssue.objects.get( issue_id=issue_id, workspace__slug=slug, @@ -374,7 +385,7 @@ class InboxIssueViewSet(BaseViewSet): ) # Update the issue state only if it is in triage state - if issue.state.name == "Triage": + if issue.state.is_triage: # Move to default state state = State.objects.filter( workspace__slug=slug, @@ -384,60 +395,60 @@ class InboxIssueViewSet(BaseViewSet): if state is not None: issue.state = state issue.save() - return Response(status=status.HTTP_204_NO_CONTENT) + + serializer = InboxIssueDetailSerializer(inbox_issue).data + return Response(serializer, status=status.HTTP_200_OK) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) else: - issue = self.get_queryset().filter(pk=issue_id).first() - serializer = IssueSerializer(issue, expand=self.expand) - return Response(serializer.data, status=status.HTTP_200_OK) + serializer = InboxIssueDetailSerializer(inbox_issue).data + return Response(serializer, status=status.HTTP_200_OK) - def retrieve(self, request, slug, project_id, inbox_id, issue_id): - issue = ( - self.get_queryset() - .filter(pk=issue_id) + def retrieve(self, request, slug, project_id, issue_id): + workspace = Workspace.objects.filter(slug=slug).first() + inbox_id = Inbox.objects.filter( + workspace_id=workspace.id, project_id=project_id + ).first() + inbox_issue = ( + InboxIssue.objects.select_related("issue") .prefetch_related( - Prefetch( - "issue_reactions", - queryset=IssueReaction.objects.select_related( - "issue", "actor" - ), - ) - ) - .prefetch_related( - Prefetch( - "issue_attachment", - queryset=IssueAttachment.objects.select_related("issue"), - ) - ) - .prefetch_related( - Prefetch( - "issue_link", - queryset=IssueLink.objects.select_related("created_by"), - ) + "issue__labels", + "issue__assignees", ) .annotate( - is_subscribed=Exists( - IssueSubscriber.objects.filter( - workspace__slug=slug, - project_id=project_id, - issue_id=OuterRef("pk"), - subscriber=request.user, - ) - ) + label_ids=Coalesce( + ArrayAgg( + "issue__labels__id", + distinct=True, + filter=~Q(issue__labels__id__isnull=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), + assignee_ids=Coalesce( + ArrayAgg( + "issue__assignees__id", + distinct=True, + filter=~Q(issue__assignees__id__isnull=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), ) + .get( + inbox_id=inbox_id.id, issue_id=issue_id, project_id=project_id + ) + ) + issue = InboxIssueDetailSerializer(inbox_issue).data + return Response( + issue, + status=status.HTTP_200_OK, + ) + + def destroy(self, request, slug, project_id, issue_id): + workspace = Workspace.objects.filter(slug=slug).first() + inbox_id = Inbox.objects.filter( + workspace_id=workspace.id, project_id=project_id ).first() - if issue is None: - return Response( - {"error": "Requested object was not found"}, - status=status.HTTP_404_NOT_FOUND, - ) - - serializer = IssueDetailSerializer(issue) - return Response(serializer.data, status=status.HTTP_200_OK) - - def destroy(self, request, slug, project_id, inbox_id, issue_id): inbox_issue = InboxIssue.objects.get( issue_id=issue_id, workspace__slug=slug, diff --git a/apiserver/plane/app/views/project/base.py b/apiserver/plane/app/views/project/base.py index 1672cd47c..50435e3a8 100644 --- a/apiserver/plane/app/views/project/base.py +++ b/apiserver/plane/app/views/project/base.py @@ -393,10 +393,11 @@ class ProjectViewSet(WebhookMixin, BaseViewSet): # Create the triage state in Backlog group State.objects.get_or_create( name="Triage", - group="backlog", + group="triage", description="Default state for managing all Inbox Issues", project_id=pk, color="#ff7700", + is_triage=True, ) project = ( diff --git a/apiserver/plane/app/views/state/base.py b/apiserver/plane/app/views/state/base.py index 7b0904490..6d55b1977 100644 --- a/apiserver/plane/app/views/state/base.py +++ b/apiserver/plane/app/views/state/base.py @@ -35,7 +35,7 @@ class StateViewSet(BaseViewSet): project__project_projectmember__is_active=True, project__archived_at__isnull=True, ) - .filter(~Q(name="Triage")) + .filter(is_triage=False) .select_related("project") .select_related("workspace") .distinct() @@ -76,7 +76,7 @@ class StateViewSet(BaseViewSet): @invalidate_cache(path="workspaces/:slug/states/", url_params=True, user=False) def destroy(self, request, slug, project_id, pk): state = State.objects.get( - ~Q(name="Triage"), + is_triage=False, pk=pk, project_id=project_id, workspace__slug=slug, diff --git a/apiserver/plane/db/migrations/0063_state_is_triage_alter_state_group.py b/apiserver/plane/db/migrations/0063_state_is_triage_alter_state_group.py new file mode 100644 index 000000000..66303dfe6 --- /dev/null +++ b/apiserver/plane/db/migrations/0063_state_is_triage_alter_state_group.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2.10 on 2024-04-02 12:18 + +from django.db import migrations, models + + +def update_project_state_group(apps, schema_editor): + State = apps.get_model("db", "State") + + # Update states in bulk + State.objects.filter(group="backlog", name="Triage").update( + is_triage=True, group="triage" + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("db", "0062_cycle_archived_at_module_archived_at_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="state", + name="is_triage", + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name="state", + name="group", + field=models.CharField( + choices=[ + ("backlog", "Backlog"), + ("unstarted", "Unstarted"), + ("started", "Started"), + ("completed", "Completed"), + ("cancelled", "Cancelled"), + ("triage", "Triage"), + ], + default="backlog", + max_length=20, + ), + ), + migrations.RunPython(update_project_state_group), + ] diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 0a59acb93..01a43abca 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -171,14 +171,14 @@ class Issue(ProjectBaseModel): from plane.db.models import State default_state = State.objects.filter( - ~models.Q(name="Triage"), + ~models.Q(is_triage=True), project=self.project, default=True, ).first() # if there is no default state assign any random state if default_state is None: random_state = State.objects.filter( - ~models.Q(name="Triage"), project=self.project + ~models.Q(is_triage=True), project=self.project ).first() self.state = random_state else: diff --git a/apiserver/plane/db/models/state.py b/apiserver/plane/db/models/state.py index ab9b780c8..28e3b25a1 100644 --- a/apiserver/plane/db/models/state.py +++ b/apiserver/plane/db/models/state.py @@ -21,10 +21,12 @@ class State(ProjectBaseModel): ("started", "Started"), ("completed", "Completed"), ("cancelled", "Cancelled"), + ("triage", "Triage") ), default="backlog", max_length=20, ) + is_triage = models.BooleanField(default=False) default = models.BooleanField(default=False) external_source = models.CharField(max_length=255, null=True, blank=True) external_id = models.CharField(max_length=255, blank=True, null=True) diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index 2c4cbd471..18ef51937 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -83,25 +83,25 @@ def date_filter(filter, date_term, queries): filter[f"{date_term}__lte"] = date_query[0] -def filter_state(params, filter, method): +def filter_state(params, filter, method, prefix=""): if method == "GET": states = [ item for item in params.get("state").split(",") if item != "null" ] states = filter_valid_uuids(states) if len(states) and "" not in states: - filter["state__in"] = states + filter[f"{prefix}state__in"] = states else: if ( params.get("state", None) and len(params.get("state")) and params.get("state") != "null" ): - filter["state__in"] = params.get("state") + filter[f"{prefix}state__in"] = params.get("state") return filter -def filter_state_group(params, filter, method): +def filter_state_group(params, filter, method, prefix=""): if method == "GET": state_group = [ item @@ -109,18 +109,18 @@ def filter_state_group(params, filter, method): if item != "null" ] if len(state_group) and "" not in state_group: - filter["state__group__in"] = state_group + filter[f"{prefix}state__group__in"] = state_group else: if ( params.get("state_group", None) and len(params.get("state_group")) and params.get("state_group") != "null" ): - filter["state__group__in"] = params.get("state_group") + filter[f"{prefix}state__group__in"] = params.get("state_group") return filter -def filter_estimate_point(params, filter, method): +def filter_estimate_point(params, filter, method, prefix=""): if method == "GET": estimate_points = [ item @@ -128,18 +128,20 @@ def filter_estimate_point(params, filter, method): if item != "null" ] if len(estimate_points) and "" not in estimate_points: - filter["estimate_point__in"] = estimate_points + filter[f"{prefix}estimate_point__in"] = estimate_points else: if ( params.get("estimate_point", None) and len(params.get("estimate_point")) and params.get("estimate_point") != "null" ): - filter["estimate_point__in"] = params.get("estimate_point") + filter[f"{prefix}estimate_point__in"] = params.get( + "estimate_point" + ) return filter -def filter_priority(params, filter, method): +def filter_priority(params, filter, method, prefix=""): if method == "GET": priorities = [ item @@ -147,47 +149,47 @@ def filter_priority(params, filter, method): if item != "null" ] if len(priorities) and "" not in priorities: - filter["priority__in"] = priorities + filter[f"{prefix}priority__in"] = priorities return filter -def filter_parent(params, filter, method): +def filter_parent(params, filter, method, prefix=""): if method == "GET": parents = [ item for item in params.get("parent").split(",") if item != "null" ] parents = filter_valid_uuids(parents) if len(parents) and "" not in parents: - filter["parent__in"] = parents + filter[f"{prefix}parent__in"] = parents else: if ( params.get("parent", None) and len(params.get("parent")) and params.get("parent") != "null" ): - filter["parent__in"] = params.get("parent") + filter[f"{prefix}parent__in"] = params.get("parent") return filter -def filter_labels(params, filter, method): +def filter_labels(params, filter, method, prefix=""): if method == "GET": labels = [ item for item in params.get("labels").split(",") if item != "null" ] labels = filter_valid_uuids(labels) if len(labels) and "" not in labels: - filter["labels__in"] = labels + filter[f"{prefix}labels__in"] = labels else: if ( params.get("labels", None) and len(params.get("labels")) and params.get("labels") != "null" ): - filter["labels__in"] = params.get("labels") + filter[f"{prefix}labels__in"] = params.get("labels") return filter -def filter_assignees(params, filter, method): +def filter_assignees(params, filter, method, prefix=""): if method == "GET": assignees = [ item @@ -196,18 +198,18 @@ def filter_assignees(params, filter, method): ] assignees = filter_valid_uuids(assignees) if len(assignees) and "" not in assignees: - filter["assignees__in"] = assignees + filter[f"{prefix}assignees__in"] = assignees else: if ( params.get("assignees", None) and len(params.get("assignees")) and params.get("assignees") != "null" ): - filter["assignees__in"] = params.get("assignees") + filter[f"{prefix}assignees__in"] = params.get("assignees") return filter -def filter_mentions(params, filter, method): +def filter_mentions(params, filter, method, prefix=""): if method == "GET": mentions = [ item @@ -216,18 +218,20 @@ def filter_mentions(params, filter, method): ] mentions = filter_valid_uuids(mentions) if len(mentions) and "" not in mentions: - filter["issue_mention__mention__id__in"] = mentions + filter[f"{prefix}issue_mention__mention__id__in"] = mentions else: if ( params.get("mentions", None) and len(params.get("mentions")) and params.get("mentions") != "null" ): - filter["issue_mention__mention__id__in"] = params.get("mentions") + filter[f"{prefix}issue_mention__mention__id__in"] = params.get( + "mentions" + ) return filter -def filter_created_by(params, filter, method): +def filter_created_by(params, filter, method, prefix=""): if method == "GET": created_bys = [ item @@ -236,94 +240,98 @@ def filter_created_by(params, filter, method): ] created_bys = filter_valid_uuids(created_bys) if len(created_bys) and "" not in created_bys: - filter["created_by__in"] = created_bys + filter[f"{prefix}created_by__in"] = created_bys else: if ( params.get("created_by", None) and len(params.get("created_by")) and params.get("created_by") != "null" ): - filter["created_by__in"] = params.get("created_by") + filter[f"{prefix}created_by__in"] = params.get("created_by") return filter -def filter_name(params, filter, method): +def filter_name(params, filter, method, prefix=""): if params.get("name", "") != "": - filter["name__icontains"] = params.get("name") + filter[f"{prefix}name__icontains"] = params.get("name") return filter -def filter_created_at(params, filter, method): +def filter_created_at(params, filter, method, prefix=""): if method == "GET": created_ats = params.get("created_at").split(",") if len(created_ats) and "" not in created_ats: date_filter( filter=filter, - date_term="created_at__date", + date_term=f"{prefix}created_at__date", queries=created_ats, ) else: if params.get("created_at", None) and len(params.get("created_at")): date_filter( filter=filter, - date_term="created_at__date", + date_term=f"{prefix}created_at__date", queries=params.get("created_at", []), ) return filter -def filter_updated_at(params, filter, method): +def filter_updated_at(params, filter, method, prefix=""): if method == "GET": updated_ats = params.get("updated_at").split(",") if len(updated_ats) and "" not in updated_ats: date_filter( filter=filter, - date_term="created_at__date", + date_term=f"{prefix}created_at__date", queries=updated_ats, ) else: if params.get("updated_at", None) and len(params.get("updated_at")): date_filter( filter=filter, - date_term="created_at__date", + date_term=f"{prefix}created_at__date", queries=params.get("updated_at", []), ) return filter -def filter_start_date(params, filter, method): +def filter_start_date(params, filter, method, prefix=""): if method == "GET": start_dates = params.get("start_date").split(",") if len(start_dates) and "" not in start_dates: date_filter( - filter=filter, date_term="start_date", queries=start_dates + filter=filter, + date_term=f"{prefix}start_date", + queries=start_dates, ) else: if params.get("start_date", None) and len(params.get("start_date")): - filter["start_date"] = params.get("start_date") + filter[f"{prefix}start_date"] = params.get("start_date") return filter -def filter_target_date(params, filter, method): +def filter_target_date(params, filter, method, prefix=""): if method == "GET": target_dates = params.get("target_date").split(",") if len(target_dates) and "" not in target_dates: date_filter( - filter=filter, date_term="target_date", queries=target_dates + filter=filter, + date_term=f"{prefix}target_date", + queries=target_dates, ) else: if params.get("target_date", None) and len(params.get("target_date")): - filter["target_date"] = params.get("target_date") + filter[f"{prefix}target_date"] = params.get("target_date") return filter -def filter_completed_at(params, filter, method): +def filter_completed_at(params, filter, method, prefix=""): if method == "GET": completed_ats = params.get("completed_at").split(",") if len(completed_ats) and "" not in completed_ats: date_filter( filter=filter, - date_term="completed_at__date", + date_term=f"{prefix}completed_at__date", queries=completed_ats, ) else: @@ -332,13 +340,13 @@ def filter_completed_at(params, filter, method): ): date_filter( filter=filter, - date_term="completed_at__date", + date_term=f"{prefix}completed_at__date", queries=params.get("completed_at", []), ) return filter -def filter_issue_state_type(params, filter, method): +def filter_issue_state_type(params, filter, method, prefix=""): type = params.get("type", "all") group = ["backlog", "unstarted", "started", "completed", "cancelled"] if type == "backlog": @@ -346,65 +354,67 @@ def filter_issue_state_type(params, filter, method): if type == "active": group = ["unstarted", "started"] - filter["state__group__in"] = group + filter[f"{prefix}state__group__in"] = group return filter -def filter_project(params, filter, method): +def filter_project(params, filter, method, prefix=""): if method == "GET": projects = [ item for item in params.get("project").split(",") if item != "null" ] projects = filter_valid_uuids(projects) if len(projects) and "" not in projects: - filter["project__in"] = projects + filter[f"{prefix}project__in"] = projects else: if ( params.get("project", None) and len(params.get("project")) and params.get("project") != "null" ): - filter["project__in"] = params.get("project") + filter[f"{prefix}project__in"] = params.get("project") return filter -def filter_cycle(params, filter, method): +def filter_cycle(params, filter, method, prefix=""): if method == "GET": cycles = [ item for item in params.get("cycle").split(",") if item != "null" ] cycles = filter_valid_uuids(cycles) if len(cycles) and "" not in cycles: - filter["issue_cycle__cycle_id__in"] = cycles + filter[f"{prefix}issue_cycle__cycle_id__in"] = cycles else: if ( params.get("cycle", None) and len(params.get("cycle")) and params.get("cycle") != "null" ): - filter["issue_cycle__cycle_id__in"] = params.get("cycle") + filter[f"{prefix}issue_cycle__cycle_id__in"] = params.get("cycle") return filter -def filter_module(params, filter, method): +def filter_module(params, filter, method, prefix=""): if method == "GET": modules = [ item for item in params.get("module").split(",") if item != "null" ] modules = filter_valid_uuids(modules) if len(modules) and "" not in modules: - filter["issue_module__module_id__in"] = modules + filter[f"{prefix}issue_module__module_id__in"] = modules else: if ( params.get("module", None) and len(params.get("module")) and params.get("module") != "null" ): - filter["issue_module__module_id__in"] = params.get("module") + filter[f"{prefix}issue_module__module_id__in"] = params.get( + "module" + ) return filter -def filter_inbox_status(params, filter, method): +def filter_inbox_status(params, filter, method, prefix=""): if method == "GET": status = [ item @@ -412,30 +422,32 @@ def filter_inbox_status(params, filter, method): if item != "null" ] if len(status) and "" not in status: - filter["issue_inbox__status__in"] = status + filter[f"{prefix}issue_inbox__status__in"] = status else: if ( params.get("inbox_status", None) and len(params.get("inbox_status")) and params.get("inbox_status") != "null" ): - filter["issue_inbox__status__in"] = params.get("inbox_status") + filter[f"{prefix}issue_inbox__status__in"] = params.get( + "inbox_status" + ) return filter -def filter_sub_issue_toggle(params, filter, method): +def filter_sub_issue_toggle(params, filter, method, prefix=""): if method == "GET": sub_issue = params.get("sub_issue", "false") if sub_issue == "false": - filter["parent__isnull"] = True + filter[f"{prefix}parent__isnull"] = True else: sub_issue = params.get("sub_issue", "false") if sub_issue == "false": - filter["parent__isnull"] = True + filter[f"{prefix}parent__isnull"] = True return filter -def filter_subscribed_issues(params, filter, method): +def filter_subscribed_issues(params, filter, method, prefix=""): if method == "GET": subscribers = [ item @@ -444,28 +456,30 @@ def filter_subscribed_issues(params, filter, method): ] subscribers = filter_valid_uuids(subscribers) if len(subscribers) and "" not in subscribers: - filter["issue_subscribers__subscriber_id__in"] = subscribers + filter[f"{prefix}issue_subscribers__subscriber_id__in"] = ( + subscribers + ) else: if ( params.get("subscriber", None) and len(params.get("subscriber")) and params.get("subscriber") != "null" ): - filter["issue_subscribers__subscriber_id__in"] = params.get( - "subscriber" + filter[f"{prefix}issue_subscribers__subscriber_id__in"] = ( + params.get("subscriber") ) return filter -def filter_start_target_date_issues(params, filter, method): +def filter_start_target_date_issues(params, filter, method, prefix=""): start_target_date = params.get("start_target_date", "false") if start_target_date == "true": - filter["target_date__isnull"] = False - filter["start_date__isnull"] = False + filter[f"{prefix}target_date__isnull"] = False + filter[f"{prefix}start_date__isnull"] = False return filter -def issue_filters(query_params, method): +def issue_filters(query_params, method, prefix=""): filter = {} ISSUE_FILTER = { @@ -497,6 +511,5 @@ def issue_filters(query_params, method): for key, value in ISSUE_FILTER.items(): if key in query_params: func = value - func(query_params, filter, method) - + func(query_params, filter, method, prefix) return filter diff --git a/apiserver/plane/utils/paginator.py b/apiserver/plane/utils/paginator.py index db0ede6ad..8cc853370 100644 --- a/apiserver/plane/utils/paginator.py +++ b/apiserver/plane/utils/paginator.py @@ -134,7 +134,7 @@ class OffsetPaginator: results=results, next=next_cursor, prev=prev_cursor, - hits=None, + hits=count, max_hits=max_hits, ) @@ -217,6 +217,7 @@ class BasePaginator: "prev_page_results": cursor_result.prev.has_results, "count": cursor_result.__len__(), "total_pages": cursor_result.max_hits, + "total_results": cursor_result.hits, "extra_stats": extra_stats, "results": results, } diff --git a/packages/types/src/common.d.ts b/packages/types/src/common.d.ts new file mode 100644 index 000000000..d347ecef1 --- /dev/null +++ b/packages/types/src/common.d.ts @@ -0,0 +1,11 @@ +export type TPaginationInfo = { + count: number; + extra_stats: string | null; + next_cursor: string; + next_page_results: boolean; + prev_cursor: string; + prev_page_results: boolean; + total_pages: number; + per_page?: number; + total_results: number; +}; diff --git a/packages/types/src/inbox.d.ts b/packages/types/src/inbox.d.ts new file mode 100644 index 000000000..09c5353fd --- /dev/null +++ b/packages/types/src/inbox.d.ts @@ -0,0 +1,76 @@ +import { TPaginationInfo } from "./common"; +import { TIssuePriorities } from "./issues"; +import { TIssue } from "./issues/base"; + +export type TInboxIssueCurrentTab = "open" | "closed"; + +export type TInboxIssueStatus = -2 | -1 | 0 | 1 | 2; + +// filters +export type TInboxIssueFilterMemberKeys = "assignee" | "created_by"; + +export type TInboxIssueFilterDateKeys = "created_at" | "updated_at"; + +export type TInboxIssueFilter = { + [key in TInboxIssueFilterMemberKeys]: string[] | undefined; +} & { + [key in TInboxIssueFilterDateKeys]: string[] | undefined; +} & { + status: TInboxIssueStatus[] | undefined; + priority: TIssuePriorities[] | undefined; + label: string[] | undefined; +}; + +// sorting filters +export type TInboxIssueSortingKeys = "order_by" | "sort_by"; + +export type TInboxIssueSortingOrderByKeys = + | "issue__created_at" + | "issue__updated_at" + | "issue__sequence_id"; + +export type TInboxIssueSortingSortByKeys = "asc" | "desc"; + +export type TInboxIssueSorting = { + order_by: TInboxIssueSortingOrderByKeys | undefined; + sort_by: TInboxIssueSortingSortByKeys | undefined; +}; + +// filtering and sorting types for query params +export type TInboxIssueSortingOrderByQueryParamKeys = + | "issue__created_at" + | "-issue__created_at" + | "issue__updated_at" + | "-issue__updated_at" + | "issue__sequence_id" + | "-issue__sequence_id"; + +export type TInboxIssueSortingOrderByQueryParam = { + order_by: TInboxIssueSortingOrderByQueryParamKeys; +}; + +export type TInboxIssuesQueryParams = { + [key in TInboxIssueFilter]: string; +} & TInboxIssueSortingOrderByQueryParam & { + per_page: number; + cursor: string; + }; + +// inbox issue types +export type TInboxIssue = { + id: string; + status: TInboxIssueStatus; + snoozed_till: Date | null; + duplicate_to: string | null; + source: string; + issue: TIssue; + created_by: string; +}; + +export type TInboxIssuePaginationInfo = TPaginationInfo & { + total_results: number; +}; + +export type TInboxIssueWithPagination = TInboxIssuePaginationInfo & { + results: TInboxIssue[]; +}; diff --git a/packages/types/src/inbox/inbox-issue.d.ts b/packages/types/src/inbox/inbox-issue.d.ts deleted file mode 100644 index c7d33f75b..000000000 --- a/packages/types/src/inbox/inbox-issue.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { TIssue } from "../issues/base"; - -export enum EInboxStatus { - PENDING = -2, - REJECT = -1, - SNOOZED = 0, - ACCEPTED = 1, - DUPLICATE = 2, -} - -export type TInboxStatus = - | EInboxStatus.PENDING - | EInboxStatus.REJECT - | EInboxStatus.SNOOZED - | EInboxStatus.ACCEPTED - | EInboxStatus.DUPLICATE; - -export type TInboxIssueDetail = { - id?: string; - source: "in-app"; - status: TInboxStatus; - duplicate_to: string | undefined; - snoozed_till: Date | undefined; -}; - -export type TInboxIssueDetailMap = Record< - string, - Record ->; // inbox_id -> issue_id -> TInboxIssueDetail - -export type TInboxIssueDetailIdMap = Record; // inbox_id -> issue_id[] - -export type TInboxIssueExtendedDetail = TIssue & { - issue_inbox: TInboxIssueDetail[]; -}; - -// property type checks -export type TInboxPendingStatus = { - status: EInboxStatus.PENDING; -}; - -export type TInboxRejectStatus = { - status: EInboxStatus.REJECT; -}; - -export type TInboxSnoozedStatus = { - status: EInboxStatus.SNOOZED; - snoozed_till: Date; -}; - -export type TInboxAcceptedStatus = { - status: EInboxStatus.ACCEPTED; -}; - -export type TInboxDuplicateStatus = { - status: EInboxStatus.DUPLICATE; - duplicate_to: string; // issue_id -}; - -export type TInboxDetailedStatus = - | TInboxPendingStatus - | TInboxRejectStatus - | TInboxSnoozedStatus - | TInboxAcceptedStatus - | TInboxDuplicateStatus; diff --git a/packages/types/src/inbox/inbox-types.d.ts b/packages/types/src/inbox/inbox-types.d.ts deleted file mode 100644 index c3ec8461e..000000000 --- a/packages/types/src/inbox/inbox-types.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TIssue } from "../issues/base"; -import type { IProjectLite } from "../project"; - -export type TInboxIssueExtended = { - completed_at: string | null; - start_date: string | null; - target_date: string | null; -}; - -export interface IInboxIssue extends TIssue, TInboxIssueExtended { - issue_inbox: { - duplicate_to: string | null; - id: string; - snoozed_till: Date | null; - source: string; - status: -2 | -1 | 0 | 1 | 2; - }[]; -} - -export interface IInbox { - id: string; - project_detail: IProjectLite; - pending_issue_count: number; - created_at: Date; - updated_at: Date; - name: string; - description: string; - is_default: boolean; - created_by: string; - updated_by: string; - project: string; - view_props: { filters: IInboxFilterOptions }; - workspace: string; -} - -export interface IInboxFilterOptions { - priority?: string[] | null; - inbox_status?: number[] | null; -} - -export interface IInboxQueryParams { - priority: string | null; - inbox_status: string | null; -} diff --git a/packages/types/src/inbox/inbox.d.ts b/packages/types/src/inbox/inbox.d.ts deleted file mode 100644 index 1b4e23e0f..000000000 --- a/packages/types/src/inbox/inbox.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -export type TInboxIssueFilterOptions = { - priority: string[]; - inbox_status: number[]; -}; - -export type TInboxIssueQueryParams = "priority" | "inbox_status"; - -export type TInboxIssueFilters = { filters: TInboxIssueFilterOptions }; - -export type TInbox = { - id: string; - name: string; - description: string; - workspace: string; - project: string; - is_default: boolean; - view_props: TInboxIssueFilters; - created_by: string; - updated_by: string; - created_at: Date; - updated_at: Date; - pending_issue_count: number; -}; - -export type TInboxDetailMap = Record; // inbox_id -> TInbox - -export type TInboxDetailIdMap = Record; // project_id -> inbox_id[] diff --git a/packages/types/src/inbox/root.d.ts b/packages/types/src/inbox/root.d.ts deleted file mode 100644 index 6fd21a4fe..000000000 --- a/packages/types/src/inbox/root.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./inbox-issue"; -export * from "./inbox-types"; -export * from "./inbox"; diff --git a/packages/types/src/index.d.ts b/packages/types/src/index.d.ts index 48d0c1448..52ea3771e 100644 --- a/packages/types/src/index.d.ts +++ b/packages/types/src/index.d.ts @@ -12,10 +12,7 @@ export * from "./pages"; export * from "./ai"; export * from "./estimate"; export * from "./importer"; - -// FIXME: Remove this after development and the refactor/mobx-store-issue branch is stable -export * from "./inbox/root"; - +export * from "./inbox"; export * from "./analytics"; export * from "./calendar"; export * from "./notifications"; @@ -29,3 +26,4 @@ export * from "./auth"; export * from "./api_token"; export * from "./instance"; export * from "./app"; +export * from "./common"; diff --git a/web/components/headers/project-inbox.tsx b/web/components/headers/project-inbox.tsx index 7ddf92380..b35c7485d 100644 --- a/web/components/headers/project-inbox.tsx +++ b/web/components/headers/project-inbox.tsx @@ -1,16 +1,15 @@ import { FC, useState } from "react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; -import { Plus } from "lucide-react"; -// hooks +import { Plus, RefreshCcw } from "lucide-react"; // ui import { Breadcrumbs, Button, LayersIcon } from "@plane/ui"; // components import { BreadcrumbLink } from "@/components/common"; import { CreateInboxIssueModal } from "@/components/inbox"; -// helper import { ProjectLogo } from "@/components/project"; -import { useProject } from "@/hooks/store"; +// hooks +import { useProject, useProjectInbox } from "@/hooks/store"; export const ProjectInboxHeader: FC = observer(() => { // states @@ -20,11 +19,12 @@ export const ProjectInboxHeader: FC = observer(() => { const { workspaceSlug } = router.query; // store hooks const { currentProjectDetails } = useProject(); + const { isLoading } = useProjectInbox(); return (
-
+
{ } /> + + {isLoading === "pagination-loading" && ( +
+ +

Syncing...

+
+ )}
diff --git a/web/components/inbox/content/inbox-issue-header.tsx b/web/components/inbox/content/inbox-issue-header.tsx new file mode 100644 index 000000000..4b1f7a114 --- /dev/null +++ b/web/components/inbox/content/inbox-issue-header.tsx @@ -0,0 +1,276 @@ +import { FC, useCallback, useEffect, useState } from "react"; +import { observer } from "mobx-react"; +import { useRouter } from "next/router"; +import { ChevronDown, ChevronUp, Clock, ExternalLink, FileStack, Link, Trash2 } from "lucide-react"; +import { Button, ControlLink, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui"; +// components +import { + AcceptIssueModal, + DeclineIssueModal, + DeleteInboxIssueModal, + InboxIssueSnoozeModal, + InboxIssueStatus, + SelectDuplicateInboxIssueModal, +} from "@/components/inbox"; +import { IssueUpdateStatus } from "@/components/issues"; +// constants +import { EUserProjectRoles } from "@/constants/project"; +// helpers +import { copyUrlToClipboard } from "@/helpers/string.helper"; +// hooks +import { useUser, useProjectInbox, useProject } from "@/hooks/store"; +// store types +import type { IInboxIssueStore } from "@/store/inbox/inbox-issue.store"; + +type TInboxIssueActionsHeader = { + workspaceSlug: string; + projectId: string; + inboxIssue: IInboxIssueStore | undefined; + isSubmitting: "submitting" | "submitted" | "saved"; +}; + +export const InboxIssueActionsHeader: FC = observer((props) => { + const { workspaceSlug, projectId, inboxIssue, isSubmitting } = props; + // states + const [isSnoozeDateModalOpen, setIsSnoozeDateModalOpen] = useState(false); + const [selectDuplicateIssue, setSelectDuplicateIssue] = useState(false); + const [acceptIssueModal, setAcceptIssueModal] = useState(false); + const [declineIssueModal, setDeclineIssueModal] = useState(false); + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + // store + const { deleteInboxIssue, inboxIssuesArray } = useProjectInbox(); + const { + currentUser, + membership: { currentProjectRole }, + } = useUser(); + const router = useRouter(); + const { getProjectById } = useProject(); + + const issue = inboxIssue?.issue; + // derived values + const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; + const canMarkAsDuplicate = isAllowed && inboxIssue?.status === -2; + const canMarkAsAccepted = isAllowed && (inboxIssue?.status === 0 || inboxIssue?.status === -2); + const canMarkAsDeclined = isAllowed && inboxIssue?.status === -2; + const canDelete = isAllowed || inboxIssue?.created_by === currentUser?.id; + const isCompleted = inboxIssue?.status === 1; + + const currentInboxIssueId = inboxIssue?.issue?.id; + + const issueLink = `${workspaceSlug}/projects/${issue?.project_id}/issues/${currentInboxIssueId}`; + + const handleInboxIssueAccept = async () => { + inboxIssue?.updateInboxIssueStatus(1); + setAcceptIssueModal(false); + }; + + const handleInboxIssueDecline = async () => { + inboxIssue?.updateInboxIssueStatus(-1); + setDeclineIssueModal(false); + }; + + const handleInboxIssueDuplicate = (issueId: string) => { + inboxIssue?.updateInboxIssueDuplicateTo(issueId); + }; + + const handleInboxSIssueSnooze = async (date: Date) => { + inboxIssue?.updateInboxIssueSnoozeTill(date); + setIsSnoozeDateModalOpen(false); + }; + + const handleInboxIssueDelete = async () => { + if (!inboxIssue || !currentInboxIssueId) return; + deleteInboxIssue(workspaceSlug, projectId, currentInboxIssueId).finally(() => { + router.push(`/${workspaceSlug}/projects/${projectId}/inbox`); + }); + }; + + const handleCopyIssueLink = () => + copyUrlToClipboard(issueLink).then(() => + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Link copied", + message: "Issue link copied to clipboard", + }) + ); + + const currentIssueIndex = inboxIssuesArray.findIndex((issue) => issue.issue.id === currentInboxIssueId) ?? 0; + + const handleInboxIssueNavigation = useCallback( + (direction: "next" | "prev") => { + if (!inboxIssuesArray || !currentInboxIssueId) return; + const activeElement = document.activeElement as HTMLElement; + if (activeElement && (activeElement.classList.contains("tiptap") || activeElement.id === "title-input")) return; + const nextIssueIndex = + direction === "next" + ? (currentIssueIndex + 1) % inboxIssuesArray.length + : (currentIssueIndex - 1 + inboxIssuesArray.length) % inboxIssuesArray.length; + const nextIssueId = inboxIssuesArray[nextIssueIndex].issue.id; + if (!nextIssueId) return; + router.push(`/${workspaceSlug}/projects/${projectId}/inbox?inboxIssueId=${nextIssueId}`); + }, + [currentInboxIssueId, currentIssueIndex, inboxIssuesArray, projectId, router, workspaceSlug] + ); + + const onKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "ArrowUp") { + handleInboxIssueNavigation("prev"); + } else if (e.key === "ArrowDown") { + handleInboxIssueNavigation("next"); + } + }, + [handleInboxIssueNavigation] + ); + + useEffect(() => { + document.addEventListener("keydown", onKeyDown); + return () => { + document.removeEventListener("keydown", onKeyDown); + }; + }, [onKeyDown]); + + if (!inboxIssue) return null; + + return ( + <> + <> + setSelectDuplicateIssue(false)} + value={inboxIssue?.duplicate_to} + onSubmit={handleInboxIssueDuplicate} + /> + + setAcceptIssueModal(false)} + onSubmit={handleInboxIssueAccept} + /> + + setDeclineIssueModal(false)} + onSubmit={handleInboxIssueDecline} + /> + + setDeleteIssueModal(false)} + onSubmit={handleInboxIssueDelete} + /> + + setIsSnoozeDateModalOpen(false)} + value={inboxIssue?.snoozed_till} + onConfirm={handleInboxSIssueSnooze} + /> + + +
+
+ {issue?.project_id && issue.sequence_id && ( +

+ {getProjectById(issue.project_id)?.identifier}-{issue.sequence_id} +

+ )} + +
+ +
+
+ +
+
+ + +
+ +
+ {canMarkAsAccepted && ( +
+ +
+ )} + + {canMarkAsDeclined && ( +
+ +
+ )} + + {isCompleted ? ( +
+ + + router.push(`/${workspaceSlug}/projects/${issue?.project_id}/issues/${currentInboxIssueId}`) + } + > + + +
+ ) : ( + + {canMarkAsAccepted && ( + setIsSnoozeDateModalOpen(true)}> +
+ + Snooze +
+
+ )} + {canMarkAsDuplicate && ( + setSelectDuplicateIssue(true)}> +
+ + Mark as duplicate +
+
+ )} + {canDelete && ( + setDeleteIssueModal(true)}> +
+ + Delete +
+
+ )} +
+ )} +
+
+
+ + ); +}); diff --git a/web/components/inbox/content/index.ts b/web/components/inbox/content/index.ts new file mode 100644 index 000000000..029365f7a --- /dev/null +++ b/web/components/inbox/content/index.ts @@ -0,0 +1,4 @@ +export * from "./root"; +export * from "./inbox-issue-header"; +export * from "./issue-properties"; +export * from "./issue-root"; diff --git a/web/components/issues/issue-detail/inbox/sidebar.tsx b/web/components/inbox/content/issue-properties.tsx similarity index 60% rename from web/components/issues/issue-detail/inbox/sidebar.tsx rename to web/components/inbox/content/issue-properties.tsx index 6472eea27..038c73476 100644 --- a/web/components/issues/issue-detail/inbox/sidebar.tsx +++ b/web/components/inbox/content/issue-properties.tsx @@ -1,60 +1,32 @@ import React from "react"; - -import { observer } from "mobx-react-lite"; - +import { observer } from "mobx-react"; import { CalendarCheck2, Signal, Tag } from "lucide-react"; - -// hooks +import { TIssue } from "@plane/types"; +import { DoubleCircleIcon, UserGroupIcon } from "@plane/ui"; // components -import { DoubleCircleIcon, StateGroupIcon, UserGroupIcon } from "@plane/ui"; import { DateDropdown, PriorityDropdown, MemberDropdown, StateDropdown } from "@/components/dropdowns"; import { IssueLabel, TIssueOperations } from "@/components/issues"; -// icons // helper import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"; -import { useIssueDetail, useProject, useProjectState } from "@/hooks/store"; type Props = { workspaceSlug: string; projectId: string; - issueId: string; + issue: Partial; issueOperations: TIssueOperations; is_editable: boolean; }; -export const InboxIssueDetailsSidebar: React.FC = observer((props) => { - const { workspaceSlug, projectId, issueId, issueOperations, is_editable } = props; - // store hooks - const { getProjectById } = useProject(); - const { projectStates } = useProjectState(); - const { - issue: { getIssueById }, - } = useIssueDetail(); - - const issue = getIssueById(issueId); - if (!issue) return <>; - - const projectDetails = issue ? getProjectById(issue.project_id) : null; +export const InboxIssueProperties: React.FC = observer((props) => { + const { workspaceSlug, projectId, issue, issueOperations, is_editable } = props; const minDate = issue.start_date ? getDate(issue.start_date) : null; minDate?.setDate(minDate.getDate()); - const currentIssueState = projectStates?.find((s) => s.id === issue.state_id); - + if (!issue || !issue?.id) return <>; return ( -
-
-
- {currentIssueState && ( - - )} -

- {projectDetails?.identifier}-{issue?.sequence_id} -

-
-
- -
+
+
Properties
@@ -64,18 +36,22 @@ export const InboxIssueDetailsSidebar: React.FC = observer((props) => { State
- issueOperations.update(workspaceSlug, projectId, issueId, { state_id: val })} - projectId={projectId?.toString() ?? ""} - disabled={!is_editable} - buttonVariant="transparent-with-text" - className="w-3/5 flex-grow group" - buttonContainerClassName="w-full text-left" - buttonClassName="text-sm" - dropdownArrow - dropdownArrowClassName="h-3.5 w-3.5 hidden group-hover:inline" - /> + {issue?.state_id && ( + + issue?.id && issueOperations.update(workspaceSlug, projectId, issue?.id, { state_id: val }) + } + projectId={projectId?.toString() ?? ""} + disabled={!is_editable} + buttonVariant="transparent-with-text" + className="w-3/5 flex-grow group" + buttonContainerClassName="w-full text-left" + buttonClassName="text-sm" + dropdownArrow + dropdownArrowClassName="h-3.5 w-3.5 hidden group-hover:inline" + /> + )}
{/* Assignee */}
@@ -84,17 +60,21 @@ export const InboxIssueDetailsSidebar: React.FC = observer((props) => { Assignees
issueOperations.update(workspaceSlug, projectId, issueId, { assignee_ids: val })} + value={issue?.assignee_ids ?? []} + onChange={(val) => + issue?.id && issueOperations.update(workspaceSlug, projectId, issue?.id, { assignee_ids: val }) + } disabled={!is_editable} projectId={projectId?.toString() ?? ""} placeholder="Add assignees" multiple - buttonVariant={issue?.assignee_ids?.length > 0 ? "transparent-without-text" : "transparent-with-text"} + buttonVariant={ + (issue?.assignee_ids || [])?.length > 0 ? "transparent-without-text" : "transparent-with-text" + } className="w-3/5 flex-grow group" buttonContainerClassName="w-full text-left" buttonClassName={`text-sm justify-between ${ - issue?.assignee_ids.length > 0 ? "" : "text-custom-text-400" + (issue?.assignee_ids || [])?.length > 0 ? "" : "text-custom-text-400" }`} hideIcon={issue.assignee_ids?.length === 0} dropdownArrow @@ -108,8 +88,10 @@ export const InboxIssueDetailsSidebar: React.FC = observer((props) => { Priority
issueOperations.update(workspaceSlug, projectId, issueId, { priority: val })} + value={issue?.priority || "none"} + onChange={(val) => + issue?.id && issueOperations.update(workspaceSlug, projectId, issue?.id, { priority: val }) + } disabled={!is_editable} buttonVariant="border-with-text" className="w-3/5 flex-grow rounded px-2 hover:bg-custom-background-80" @@ -129,9 +111,10 @@ export const InboxIssueDetailsSidebar: React.FC = observer((props) => {
- issueOperations.update(workspaceSlug, projectId, issueId, { + issue?.id && + issueOperations.update(workspaceSlug, projectId, issue?.id, { target_date: val ? renderFormattedPayloadDate(val) : null, }) } @@ -152,16 +135,18 @@ export const InboxIssueDetailsSidebar: React.FC = observer((props) => { Labels
- - issueOperations.update(workspaceSlug, projectId, issueId, { label_ids: val }) - } - /> + {issue?.id && ( + + issue?.id && issueOperations.update(workspaceSlug, projectId, issue?.id, { label_ids: val }) + } + /> + )}
diff --git a/web/components/inbox/content/issue-root.tsx b/web/components/inbox/content/issue-root.tsx new file mode 100644 index 000000000..b493b573b --- /dev/null +++ b/web/components/inbox/content/issue-root.tsx @@ -0,0 +1,174 @@ +import { Dispatch, SetStateAction, useEffect, useMemo } from "react"; +import { observer } from "mobx-react"; +import { useRouter } from "next/router"; +import { TIssue } from "@plane/types"; +import { Loader, TOAST_TYPE, setToast } from "@plane/ui"; +// components +import { InboxIssueProperties } from "@/components/inbox/content"; +import { + IssueDescriptionInput, + IssueTitleInput, + IssueActivity, + IssueReaction, + TIssueOperations, +} from "@/components/issues"; +// hooks +import { useEventTracker, useProjectInbox, useUser } from "@/hooks/store"; +import useReloadConfirmations from "@/hooks/use-reload-confirmation"; +// store types +import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store"; + +type Props = { + workspaceSlug: string; + projectId: string; + inboxIssue: IInboxIssueStore; + is_editable: boolean; + isSubmitting: "submitting" | "submitted" | "saved"; + setIsSubmitting: Dispatch>; +}; + +export const InboxIssueMainContent: React.FC = observer((props) => { + const router = useRouter(); + const { workspaceSlug, projectId, inboxIssue, is_editable, isSubmitting, setIsSubmitting } = props; + // hooks + const { currentUser } = useUser(); + const { isLoading } = useProjectInbox(); + const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting"); + const { captureIssueEvent } = useEventTracker(); + + useEffect(() => { + if (isSubmitting === "submitted") { + setShowAlert(false); + setTimeout(async () => { + setIsSubmitting("saved"); + }, 3000); + } else if (isSubmitting === "submitting") { + setShowAlert(true); + } + }, [isSubmitting, setShowAlert, setIsSubmitting]); + + const issue = inboxIssue.issue; + if (!issue) return <>; + + const issueDescription = + issue.description_html !== undefined || issue.description_html !== null + ? issue.description_html != "" + ? issue.description_html + : "

" + : undefined; + + const issueOperations: TIssueOperations = useMemo( + () => ({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fetch: async (workspaceSlug: string, projectId: string, issueId: string) => { + try { + return; + } catch (error) { + setToast({ + title: "Issue fetch failed", + type: TOAST_TYPE.ERROR, + message: "Issue fetch failed", + }); + } + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + remove: async (workspaceSlug: string, projectId: string, issueId: string) => { + try { + return; + } catch (error) { + setToast({ + title: "Issue remove failed", + type: TOAST_TYPE.ERROR, + message: "Issue remove failed", + }); + } + }, + update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => { + try { + await inboxIssue.updateIssue(data); + captureIssueEvent({ + eventName: "Inbox issue updated", + payload: { ...data, state: "SUCCESS", element: "Inbox" }, + updates: { + changed_property: Object.keys(data).join(","), + change_details: Object.values(data).join(","), + }, + path: router.asPath, + }); + } catch (error) { + setToast({ + title: "Issue update failed", + type: TOAST_TYPE.ERROR, + message: "Issue update failed", + }); + captureIssueEvent({ + eventName: "Inbox issue updated", + payload: { state: "SUCCESS", element: "Inbox" }, + updates: { + changed_property: Object.keys(data).join(","), + change_details: Object.values(data).join(","), + }, + path: router.asPath, + }); + } + }, + }), + [inboxIssue] + ); + + if (!issue?.project_id || !issue?.id) return <>; + return ( + <> +
+ setIsSubmitting(value)} + issueOperations={issueOperations} + disabled={!is_editable} + value={issue.name} + /> + + {isLoading ? ( + + + + ) : ( + setIsSubmitting(value)} + /> + )} + + {currentUser && ( + + )} +
+ + + +
+ +
+ + ); +}); diff --git a/web/components/inbox/content/root.tsx b/web/components/inbox/content/root.tsx index 389876812..12cfb836d 100644 --- a/web/components/inbox/content/root.tsx +++ b/web/components/inbox/content/root.tsx @@ -1,86 +1,62 @@ -import { FC } from "react"; +import { FC, useState } from "react"; import { observer } from "mobx-react"; -import { Inbox } from "lucide-react"; -// hooks -import { Loader } from "@plane/ui"; -import { InboxIssueActionsHeader } from "@/components/inbox"; -import { InboxIssueDetailRoot } from "@/components/issues/issue-detail/inbox"; -import { useInboxIssues } from "@/hooks/store"; -// components -// ui +import useSWR from "swr"; +import { InboxIssueActionsHeader, InboxIssueMainContent } from "@/components/inbox"; +import { EUserProjectRoles } from "@/constants/project"; +import { useProjectInbox, useUser } from "@/hooks/store"; type TInboxContentRoot = { workspaceSlug: string; projectId: string; - inboxId: string; - inboxIssueId: string | undefined; + inboxIssueId: string; }; export const InboxContentRoot: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId, inboxIssueId } = props; + const { workspaceSlug, projectId, inboxIssueId } = props; + // states + const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); // hooks + const { fetchInboxIssueById, getIssueInboxByIssueId } = useProjectInbox(); + const inboxIssue = getIssueInboxByIssueId(inboxIssueId); const { - issues: { loader, getInboxIssuesByInboxId }, - } = useInboxIssues(); + membership: { currentProjectRole }, + } = useUser(); - const inboxIssuesList = inboxId ? getInboxIssuesByInboxId(inboxId) : undefined; + useSWR( + workspaceSlug && projectId && inboxIssueId + ? `PROJECT_INBOX_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${inboxIssueId}` + : null, + () => { + workspaceSlug && projectId && inboxIssueId && fetchInboxIssueById(workspaceSlug, projectId, inboxIssueId); + }, + { revalidateOnFocus: false } + ); + const is_editable = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; + + if (!inboxIssue) return <>; return ( <> - {loader === "init-loader" ? ( - -
- - - - -
-
- - - - -
-
- ) : ( - <> - {!inboxIssueId ? ( -
-
-
- - {inboxIssuesList && inboxIssuesList.length > 0 ? ( - - {inboxIssuesList?.length} issues found. Select an issue from the sidebar to view its details. - - ) : ( - No issues found - )} -
-
-
- ) : ( -
-
- -
-
- -
-
- )} - - )} +
+
+ +
+
+ +
+
); }); diff --git a/web/components/inbox/inbox-filter/applied-filters/date.tsx b/web/components/inbox/inbox-filter/applied-filters/date.tsx new file mode 100644 index 000000000..bce7a0487 --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/date.tsx @@ -0,0 +1,66 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { X } from "lucide-react"; +import { TInboxIssueFilterDateKeys } from "@plane/types"; +// constants +import { DATE_BEFORE_FILTER_OPTIONS } from "@/constants/filters"; +// helpers +import { renderFormattedDate } from "@/helpers/date-time.helper"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +type InboxIssueAppliedFiltersDate = { + filterKey: TInboxIssueFilterDateKeys; + label: string; +}; + +export const InboxIssueAppliedFiltersDate: FC = observer((props) => { + const { filterKey, label } = props; + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // derived values + const filteredValues = inboxFilters?.[filterKey] || []; + const currentOptionDetail = (date: string) => { + const currentDate = DATE_BEFORE_FILTER_OPTIONS.find((d) => d.value === date); + if (currentDate) return currentDate; + const dateSplit = date.split(";"); + return { + name: `${dateSplit[1].charAt(0).toUpperCase() + dateSplit[1].slice(1)} ${renderFormattedDate(dateSplit[0])}`, + value: date, + }; + }; + + const handleFilterValue = (value: string): string[] => + filteredValues?.includes(value) ? filteredValues.filter((v) => v !== value) : [...filteredValues, value]; + + const clearFilter = () => handleInboxIssueFilters(filterKey, undefined); + + if (filteredValues.length === 0) return <>; + return ( +
+
{label}
+ {filteredValues.map((value) => { + const optionDetail = currentOptionDetail(value); + if (!optionDetail) return <>; + return ( +
+
{optionDetail?.name}
+
handleInboxIssueFilters(filterKey, handleFilterValue(optionDetail?.value))} + > + +
+
+ ); + })} + +
+ +
+
+ ); +}); diff --git a/web/components/inbox/inbox-filter/applied-filters/index.ts b/web/components/inbox/inbox-filter/applied-filters/index.ts new file mode 100644 index 000000000..35f0bc261 --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/index.ts @@ -0,0 +1,6 @@ +export * from "./root"; +export * from "./status"; +export * from "./priority"; +export * from "./member"; +export * from "./label"; +export * from "./date"; diff --git a/web/components/inbox/inbox-filter/applied-filters/label.tsx b/web/components/inbox/inbox-filter/applied-filters/label.tsx new file mode 100644 index 000000000..b028a1773 --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/label.tsx @@ -0,0 +1,55 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { X } from "lucide-react"; +// hooks +import { useLabel, useProjectInbox } from "@/hooks/store"; + +const LabelIcons = ({ color }: { color: string }) => ( + +); + +export const InboxIssueAppliedFiltersLabel: FC = observer(() => { + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + const { getLabelById } = useLabel(); + // derived values + const filteredValues = inboxFilters?.label || []; + const currentOptionDetail = (labelId: string) => getLabelById(labelId) || undefined; + + const handleFilterValue = (value: string): string[] => + filteredValues?.includes(value) ? filteredValues.filter((v) => v !== value) : [...filteredValues, value]; + + const clearFilter = () => handleInboxIssueFilters("label", undefined); + + if (filteredValues.length === 0) return <>; + return ( +
+
Label
+ {filteredValues.map((value) => { + const optionDetail = currentOptionDetail(value); + if (!optionDetail) return <>; + return ( +
+
+ +
+
{optionDetail?.name}
+
handleInboxIssueFilters("label", handleFilterValue(value))} + > + +
+
+ ); + })} + +
+ +
+
+ ); +}); diff --git a/web/components/inbox/inbox-filter/applied-filters/member.tsx b/web/components/inbox/inbox-filter/applied-filters/member.tsx new file mode 100644 index 000000000..5d488a23c --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/member.tsx @@ -0,0 +1,59 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { X } from "lucide-react"; +import { TInboxIssueFilterMemberKeys } from "@plane/types"; +import { Avatar } from "@plane/ui"; +// hooks +import { useMember, useProjectInbox } from "@/hooks/store"; + +type InboxIssueAppliedFiltersMember = { + filterKey: TInboxIssueFilterMemberKeys; + label: string; +}; + +export const InboxIssueAppliedFiltersMember: FC = observer((props) => { + const { filterKey, label } = props; + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + const { getUserDetails } = useMember(); + // derived values + const filteredValues = inboxFilters?.[filterKey] || []; + const currentOptionDetail = (memberId: string) => getUserDetails(memberId) || undefined; + + const handleFilterValue = (value: string): string[] => + filteredValues?.includes(value) ? filteredValues.filter((v) => v !== value) : [...filteredValues, value]; + + const clearFilter = () => handleInboxIssueFilters(filterKey, undefined); + + if (filteredValues.length === 0) return <>; + return ( +
+
{label}
+ {filteredValues.map((value) => { + const optionDetail = currentOptionDetail(value); + if (!optionDetail) return <>; + return ( +
+
+ +
+
{optionDetail?.display_name}
+
handleInboxIssueFilters(filterKey, handleFilterValue(value))} + > + +
+
+ ); + })} + +
+ +
+
+ ); +}); diff --git a/web/components/inbox/inbox-filter/applied-filters/priority.tsx b/web/components/inbox/inbox-filter/applied-filters/priority.tsx new file mode 100644 index 000000000..e5a51d188 --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/priority.tsx @@ -0,0 +1,55 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { X } from "lucide-react"; +import { TIssuePriorities } from "@plane/types"; +import { PriorityIcon } from "@plane/ui"; +// constants +import { ISSUE_PRIORITIES } from "@/constants/issue"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +export const InboxIssueAppliedFiltersPriority: FC = observer(() => { + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // derived values + const filteredValues = inboxFilters?.priority || []; + const currentOptionDetail = (priority: TIssuePriorities) => + ISSUE_PRIORITIES.find((p) => p.key === priority) || undefined; + + const handleFilterValue = (value: TIssuePriorities): TIssuePriorities[] => + filteredValues?.includes(value) ? filteredValues.filter((v) => v !== value) : [...filteredValues, value]; + + const clearFilter = () => handleInboxIssueFilters("priority", undefined); + + if (filteredValues.length === 0) return <>; + return ( +
+
Priority
+ {filteredValues.map((value) => { + const optionDetail = currentOptionDetail(value); + if (!optionDetail) return <>; + return ( +
+
+ +
+
{optionDetail?.title}
+
handleInboxIssueFilters("priority", handleFilterValue(optionDetail?.key))} + > + +
+
+ ); + })} + +
+ +
+
+ ); +}); diff --git a/web/components/inbox/inbox-filter/applied-filters/root.tsx b/web/components/inbox/inbox-filter/applied-filters/root.tsx new file mode 100644 index 000000000..8baf86df2 --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/root.tsx @@ -0,0 +1,36 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +// components +import { + InboxIssueAppliedFiltersStatus, + InboxIssueAppliedFiltersPriority, + InboxIssueAppliedFiltersMember, + InboxIssueAppliedFiltersLabel, + InboxIssueAppliedFiltersDate, +} from "@/components/inbox"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +export const InboxIssueAppliedFilters: FC = observer(() => { + const { getAppliedFiltersCount } = useProjectInbox(); + + if (getAppliedFiltersCount === 0) return <>; + return ( +
+ {/* status */} + + {/* priority */} + + {/* assignees */} + + {/* created_by */} + + {/* label */} + + {/* created_at */} + + {/* updated_at */} + +
+ ); +}); diff --git a/web/components/inbox/inbox-filter/applied-filters/status.tsx b/web/components/inbox/inbox-filter/applied-filters/status.tsx new file mode 100644 index 000000000..a4ec1a37e --- /dev/null +++ b/web/components/inbox/inbox-filter/applied-filters/status.tsx @@ -0,0 +1,57 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { X } from "lucide-react"; +import { TInboxIssueStatus } from "@plane/types"; +// constants +import { INBOX_STATUS } from "@/constants/inbox"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +export const InboxIssueAppliedFiltersStatus: FC = observer(() => { + // hooks + const { currentTab, inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // derived values + const filteredValues = inboxFilters?.status || []; + const currentOptionDetail = (status: TInboxIssueStatus) => INBOX_STATUS.find((s) => s.status === status) || undefined; + + const handleFilterValue = (value: TInboxIssueStatus): TInboxIssueStatus[] => + filteredValues?.includes(value) ? filteredValues.filter((v) => v !== value) : [...filteredValues, value]; + + const clearFilter = () => handleInboxIssueFilters("status", undefined); + + if (filteredValues.length === 0) return <>; + return ( +
+
Status
+ {filteredValues.map((value) => { + const optionDetail = currentOptionDetail(value); + if (!optionDetail) return <>; + return ( +
+
+ +
+
{optionDetail?.title}
+ {currentTab === "closed" && handleFilterValue(optionDetail?.status).length >= 1 && ( +
handleInboxIssueFilters("status", handleFilterValue(optionDetail?.status))} + > + +
+ )} +
+ ); + })} + + {currentTab === "closed" && filteredValues.length > 1 && ( +
+ +
+ )} +
+ ); +}); diff --git a/web/components/inbox/inbox-filter/filters/date.tsx b/web/components/inbox/inbox-filter/filters/date.tsx new file mode 100644 index 000000000..12aba01ef --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/date.tsx @@ -0,0 +1,97 @@ +import { FC, useState } from "react"; +import concat from "lodash/concat"; +import pull from "lodash/pull"; +import uniq from "lodash/uniq"; +import { observer } from "mobx-react"; +import { TInboxIssueFilterDateKeys } from "@plane/types"; +// components +import { DateFilterModal } from "@/components/core"; +import { FilterHeader, FilterOption } from "@/components/issues"; +// constants +import { DATE_BEFORE_FILTER_OPTIONS } from "@/constants/filters"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +type Props = { + filterKey: TInboxIssueFilterDateKeys; + label?: string; + searchQuery: string; +}; + +const isDate = (date: string) => { + const datePattern = /^\d{4}-\d{2}-\d{2}$/; + return datePattern.test(date); +}; + +export const FilterDate: FC = observer((props) => { + const { filterKey, label, searchQuery } = props; + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // state + const [previewEnabled, setPreviewEnabled] = useState(true); + const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false); + // derived values + const filterValue: string[] = inboxFilters?.[filterKey] || []; + const appliedFiltersCount = filterValue?.length ?? 0; + const filteredOptions = DATE_BEFORE_FILTER_OPTIONS.filter((d) => + d.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + const handleFilterValue = (value: string): string[] => + filterValue?.includes(value) ? pull(filterValue, value) : uniq(concat(filterValue, value)); + + const handleCustomFilterValue = (value: string[]): string[] => { + const finalOptions: string[] = [...filterValue]; + value.forEach((v) => (finalOptions?.includes(v) ? pull(finalOptions, v) : finalOptions.push(v))); + return uniq(finalOptions); + }; + + const isCustomDateSelected = () => { + const isValidDateSelected = filterValue?.filter((f) => isDate(f.split(";")[0])) || []; + return isValidDateSelected.length > 0 ? true : false; + }; + + const handleCustomDate = () => { + if (isCustomDateSelected()) { + const updateAppliedFilters = filterValue?.filter((f) => isDate(f.split(";")[0])) || []; + handleInboxIssueFilters(filterKey, handleCustomFilterValue(updateAppliedFilters)); + } else setIsDateFilterModalOpen(true); + }; + return ( + <> + {isDateFilterModalOpen && ( + setIsDateFilterModalOpen(false)} + isOpen={isDateFilterModalOpen} + onSelect={(val) => handleInboxIssueFilters(filterKey, handleCustomFilterValue(val))} + title="Created date" + /> + )} + 0 ? ` (${appliedFiltersCount})` : ""}`} + isPreviewEnabled={previewEnabled} + handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {filteredOptions.length > 0 ? ( + <> + {filteredOptions.map((option) => ( + handleInboxIssueFilters(filterKey, handleFilterValue(option.value))} + title={option.name} + multiple + /> + ))} + + + ) : ( +

No matches found

+ )} +
+ )} + + ); +}); diff --git a/web/components/inbox/inbox-filter/filters/filter-selection.tsx b/web/components/inbox/inbox-filter/filters/filter-selection.tsx new file mode 100644 index 000000000..46f959a2d --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/filter-selection.tsx @@ -0,0 +1,87 @@ +import { FC, useState } from "react"; +import { observer } from "mobx-react"; +import { Search, X } from "lucide-react"; +// components +import { + FilterStatus, + FilterPriority, + FilterMember, + FilterDate, + FilterLabels, +} from "@/components/inbox/inbox-filter/filters"; +// hooks +import { useMember, useLabel } from "@/hooks/store"; + +export const InboxIssueFilterSelection: FC = observer(() => { + // hooks + const { + project: { projectMemberIds }, + } = useMember(); + const { projectLabels } = useLabel(); + // states + const [filtersSearchQuery, setFiltersSearchQuery] = useState(""); + + return ( +
+
+
+ + setFiltersSearchQuery(e.target.value)} + autoFocus + /> + {filtersSearchQuery !== "" && ( + + )} +
+
+ +
+ {/* status */} +
+ +
+ {/* Priority */} +
+ +
+ {/* assignees */} +
+ +
+ {/* Created By */} +
+ +
+ {/* Labels */} +
+ +
+ {/* Created at */} +
+ +
+ {/* Updated at */} +
+ +
+
+
+ ); +}); diff --git a/web/components/inbox/inbox-filter/filters/index.ts b/web/components/inbox/inbox-filter/filters/index.ts new file mode 100644 index 000000000..a389dda9d --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/index.ts @@ -0,0 +1,6 @@ +export * from "./filter-selection"; +export * from "./status"; +export * from "./priority"; +export * from "./labels"; +export * from "./members"; +export * from "./date"; diff --git a/web/components/inbox/inbox-filter/filters/labels.tsx b/web/components/inbox/inbox-filter/filters/labels.tsx new file mode 100644 index 000000000..cf55623c8 --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/labels.tsx @@ -0,0 +1,88 @@ +import { FC, useState } from "react"; +import { observer } from "mobx-react"; +import { IIssueLabel } from "@plane/types"; +import { Loader } from "@plane/ui"; +// components +import { FilterHeader, FilterOption } from "@/components/issues"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +const LabelIcons = ({ color }: { color: string }) => ( + +); + +type Props = { + labels: IIssueLabel[] | undefined; + searchQuery: string; +}; + +export const FilterLabels: FC = observer((props) => { + const { labels, searchQuery } = props; + + const [itemsToRender, setItemsToRender] = useState(5); + const [previewEnabled, setPreviewEnabled] = useState(true); + + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + + const filterValue = inboxFilters?.label || []; + + const appliedFiltersCount = filterValue?.length ?? 0; + + const filteredOptions = labels?.filter((label) => label.name.toLowerCase().includes(searchQuery.toLowerCase())); + + const handleViewToggle = () => { + if (!filteredOptions) return; + + if (itemsToRender === filteredOptions.length) setItemsToRender(5); + else setItemsToRender(filteredOptions.length); + }; + + const handleFilterValue = (value: string): string[] => + filterValue?.includes(value) ? filterValue.filter((v) => v !== value) : [...filterValue, value]; + + return ( + <> + 0 ? ` (${appliedFiltersCount})` : ""}`} + isPreviewEnabled={previewEnabled} + handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {filteredOptions ? ( + filteredOptions.length > 0 ? ( + <> + {filteredOptions.slice(0, itemsToRender).map((label) => ( + handleInboxIssueFilters("label", handleFilterValue(label.id))} + icon={} + title={label.name} + /> + ))} + {filteredOptions.length > 5 && ( + + )} + + ) : ( +

No matches found

+ ) + ) : ( + + + + + + )} +
+ )} + + ); +}); diff --git a/web/components/inbox/inbox-filter/filters/members.tsx b/web/components/inbox/inbox-filter/filters/members.tsx new file mode 100644 index 000000000..f2776104b --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/members.tsx @@ -0,0 +1,102 @@ +import { FC, useMemo, useState } from "react"; +import sortBy from "lodash/sortBy"; +import { observer } from "mobx-react"; +import { TInboxIssueFilterMemberKeys } from "@plane/types"; +import { Avatar, Loader } from "@plane/ui"; +// components +import { FilterHeader, FilterOption } from "@/components/issues"; +// hooks +import { useMember, useProjectInbox } from "@/hooks/store"; + +type Props = { + filterKey: TInboxIssueFilterMemberKeys; + label?: string; + memberIds: string[] | undefined; + searchQuery: string; +}; + +export const FilterMember: FC = observer((props: Props) => { + const { filterKey, label = "Members", memberIds, searchQuery } = props; + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + const { getUserDetails } = useMember(); + // states + const [itemsToRender, setItemsToRender] = useState(5); + const [previewEnabled, setPreviewEnabled] = useState(true); + // derived values + const filterValue = inboxFilters?.[filterKey] || []; + const appliedFiltersCount = filterValue?.length ?? 0; + + const sortedOptions = useMemo(() => { + const filteredOptions = (memberIds || []).filter((memberId) => + getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + return sortBy(filteredOptions, [ + (memberId) => !filterValue.includes(memberId), + (memberId) => getUserDetails(memberId)?.display_name.toLowerCase(), + ]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchQuery]); + + const handleViewToggle = () => { + if (!sortedOptions) return; + + if (itemsToRender === sortedOptions.length) setItemsToRender(5); + else setItemsToRender(sortedOptions.length); + }; + + const handleFilterValue = (value: string): string[] => + filterValue?.includes(value) ? filterValue.filter((v) => v !== value) : [...filterValue, value]; + + return ( + <> + 0 ? ` (${appliedFiltersCount})` : ""}`} + isPreviewEnabled={previewEnabled} + handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {sortedOptions ? ( + sortedOptions.length > 0 ? ( + <> + {sortedOptions.slice(0, itemsToRender).map((memberId) => { + const member = getUserDetails(memberId); + + if (!member) return null; + return ( + handleInboxIssueFilters(filterKey, handleFilterValue(member.id))} + icon={} + title={member.display_name} + /> + ); + })} + {sortedOptions.length > 5 && ( + + )} + + ) : ( +

No matches found

+ ) + ) : ( + + + + + + )} +
+ )} + + ); +}); diff --git a/web/components/inbox/inbox-filter/filters/priority.tsx b/web/components/inbox/inbox-filter/filters/priority.tsx new file mode 100644 index 000000000..0639623e4 --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/priority.tsx @@ -0,0 +1,56 @@ +import { FC, useState } from "react"; +import { observer } from "mobx-react"; +import { TIssuePriorities } from "@plane/types"; +import { PriorityIcon } from "@plane/ui"; +// components +import { FilterHeader, FilterOption } from "@/components/issues"; +// constants +import { ISSUE_PRIORITIES } from "@/constants/issue"; +// hooks +import { useProjectInbox } from "@/hooks/store/use-project-inbox"; + +type Props = { + searchQuery: string; +}; + +export const FilterPriority: FC = observer((props) => { + const { searchQuery } = props; + // hooks + const { inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // states + const [previewEnabled, setPreviewEnabled] = useState(true); + // derived values + const filterValue = inboxFilters?.priority || []; + const appliedFiltersCount = filterValue?.length ?? 0; + const filteredOptions = ISSUE_PRIORITIES.filter((p) => p.key.includes(searchQuery.toLowerCase())); + + const handleFilterValue = (value: TIssuePriorities): TIssuePriorities[] => + filterValue?.includes(value) ? filterValue.filter((v) => v !== value) : [...filterValue, value]; + + return ( + <> + 0 ? ` (${appliedFiltersCount})` : ""}`} + isPreviewEnabled={previewEnabled} + handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {filteredOptions.length > 0 ? ( + filteredOptions.map((priority) => ( + handleInboxIssueFilters("priority", handleFilterValue(priority.key))} + icon={} + title={priority.title} + /> + )) + ) : ( +

No matches found

+ )} +
+ )} + + ); +}); diff --git a/web/components/inbox/inbox-filter/filters/status.tsx b/web/components/inbox/inbox-filter/filters/status.tsx new file mode 100644 index 000000000..ca79d882f --- /dev/null +++ b/web/components/inbox/inbox-filter/filters/status.tsx @@ -0,0 +1,68 @@ +import { FC, useState } from "react"; +import { observer } from "mobx-react"; +// types +import { TInboxIssueStatus } from "@plane/types"; +// components +import { FilterHeader, FilterOption } from "@/components/issues"; +// constants +import { INBOX_STATUS } from "@/constants/inbox"; +// hooks +import { useProjectInbox } from "@/hooks/store/use-project-inbox"; + +type Props = { + searchQuery: string; +}; + +export const FilterStatus: FC = observer((props) => { + const { searchQuery } = props; + // hooks + const { currentTab, inboxFilters, handleInboxIssueFilters } = useProjectInbox(); + // states + const [previewEnabled, setPreviewEnabled] = useState(true); + // derived values + const filterValue = inboxFilters?.status || []; + const appliedFiltersCount = filterValue?.length ?? 0; + const filteredOptions = INBOX_STATUS.filter( + (s) => + ((currentTab === "open" && [-2].includes(s.status)) || + (currentTab === "closed" && [-1, 0, 1, 2].includes(s.status))) && + s.key.includes(searchQuery.toLowerCase()) + ); + + const handleFilterValue = (value: TInboxIssueStatus): TInboxIssueStatus[] => + filterValue?.includes(value) ? filterValue.filter((v) => v !== value) : [...filterValue, value]; + + const handleStatusFilterSelect = (status: TInboxIssueStatus) => { + if (currentTab === "closed") { + const selectedStatus = handleFilterValue(status); + if (selectedStatus.length >= 1) handleInboxIssueFilters("status", selectedStatus); + } + }; + + return ( + <> + 0 ? ` (${appliedFiltersCount})` : ""}`} + isPreviewEnabled={previewEnabled} + handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {filteredOptions.length > 0 ? ( + filteredOptions.map((status) => ( + handleStatusFilterSelect(status.status)} + icon={} + title={status.title} + /> + )) + ) : ( +

No matches found

+ )} +
+ )} + + ); +}); diff --git a/web/components/inbox/inbox-filter/index.ts b/web/components/inbox/inbox-filter/index.ts new file mode 100644 index 000000000..20ec09a35 --- /dev/null +++ b/web/components/inbox/inbox-filter/index.ts @@ -0,0 +1,4 @@ +export * from "./root"; +export * from "./filters"; +export * from "./sorting"; +export * from "./applied-filters"; diff --git a/web/components/inbox/inbox-filter/root.tsx b/web/components/inbox/inbox-filter/root.tsx new file mode 100644 index 000000000..b3a2dc2c4 --- /dev/null +++ b/web/components/inbox/inbox-filter/root.tsx @@ -0,0 +1,18 @@ +import { FC } from "react"; +import { ListFilter } from "lucide-react"; +// components +import { InboxIssueFilterSelection, InboxIssueOrderByDropdown } from "@/components/inbox/inbox-filter"; +import { FiltersDropdown } from "@/components/issues"; + +export const FiltersRoot: FC = () => ( +
+
+ } title="Filters" placement="bottom-end"> + + +
+
+ +
+
+); diff --git a/web/components/inbox/inbox-filter/sorting/index.ts b/web/components/inbox/inbox-filter/sorting/index.ts new file mode 100644 index 000000000..d6db844ce --- /dev/null +++ b/web/components/inbox/inbox-filter/sorting/index.ts @@ -0,0 +1 @@ +export * from "./order-by"; diff --git a/web/components/inbox/inbox-filter/sorting/order-by.tsx b/web/components/inbox/inbox-filter/sorting/order-by.tsx new file mode 100644 index 000000000..c01c9977e --- /dev/null +++ b/web/components/inbox/inbox-filter/sorting/order-by.tsx @@ -0,0 +1,58 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { ArrowDownWideNarrow, ArrowUpWideNarrow, Check, ChevronDown } from "lucide-react"; +import { CustomMenu, getButtonStyling } from "@plane/ui"; +// constants +import { INBOX_ISSUE_ORDER_BY_OPTIONS, INBOX_ISSUE_SORT_BY_OPTIONS } from "@/constants/inbox"; +// helpers +import { cn } from "@/helpers/common.helper"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +export const InboxIssueOrderByDropdown: FC = observer(() => { + // hooks + const { inboxSorting, handleInboxIssueSorting } = useProjectInbox(); + const orderByDetails = + INBOX_ISSUE_ORDER_BY_OPTIONS.find((option) => inboxSorting?.order_by?.includes(option.key)) || undefined; + + return ( + + {inboxSorting?.sort_by === "asc" ? ( + + ) : ( + + )} + {orderByDetails?.label || "Order By"} + +
+ } + placement="bottom-end" + maxHeight="lg" + closeOnSelect + > + {INBOX_ISSUE_ORDER_BY_OPTIONS.map((option) => ( + handleInboxIssueSorting("order_by", option.key)} + > + {option.label} + {inboxSorting?.order_by?.includes(option.key) && } + + ))} +
+ {INBOX_ISSUE_SORT_BY_OPTIONS.map((option) => ( + handleInboxIssueSorting("sort_by", option.key)} + > + {option.label} + {inboxSorting?.sort_by?.includes(option.key) && } + + ))} + + ); +}); diff --git a/web/components/inbox/inbox-issue-actions.tsx b/web/components/inbox/inbox-issue-actions.tsx deleted file mode 100644 index 4c8a21592..000000000 --- a/web/components/inbox/inbox-issue-actions.tsx +++ /dev/null @@ -1,364 +0,0 @@ -import { FC, useCallback, useEffect, useMemo, useState } from "react"; -import { observer } from "mobx-react-lite"; -import { useRouter } from "next/router"; -import { DayPicker } from "react-day-picker"; -import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Trash2, XCircle } from "lucide-react"; -import { Popover } from "@headlessui/react"; -// icons -import type { TInboxDetailedStatus } from "@plane/types"; -// ui -import { Button, TOAST_TYPE, setToast } from "@plane/ui"; -// components -import { - AcceptIssueModal, - DeclineIssueModal, - DeleteInboxIssueModal, - SelectDuplicateInboxIssueModal, -} from "@/components/inbox"; -import { ISSUE_DELETED } from "@/constants/event-tracker"; -import { EUserProjectRoles } from "@/constants/project"; -// hooks -import { getDate } from "@/helpers/date-time.helper"; -import { useUser, useInboxIssues, useIssueDetail, useWorkspace, useEventTracker } from "@/hooks/store"; -// types -//helpers - -type TInboxIssueActionsHeader = { - workspaceSlug: string; - projectId: string; - inboxId: string; - inboxIssueId: string | undefined; -}; - -type TInboxIssueOperations = { - updateInboxIssueStatus: (data: TInboxDetailedStatus) => Promise; - removeInboxIssue: () => Promise; -}; - -export const InboxIssueActionsHeader: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId, inboxIssueId } = props; - // router - const router = useRouter(); - // hooks - const { captureIssueEvent } = useEventTracker(); - const { currentWorkspace } = useWorkspace(); - const { - issues: { getInboxIssuesByInboxId, getInboxIssueByIssueId, updateInboxIssueStatus, removeInboxIssue }, - } = useInboxIssues(); - const { - issue: { getIssueById }, - } = useIssueDetail(); - const { - currentUser, - membership: { currentProjectRole }, - } = useUser(); - - // states - const [date, setDate] = useState(new Date()); - const [selectDuplicateIssue, setSelectDuplicateIssue] = useState(false); - const [acceptIssueModal, setAcceptIssueModal] = useState(false); - const [declineIssueModal, setDeclineIssueModal] = useState(false); - const [deleteIssueModal, setDeleteIssueModal] = useState(false); - - // derived values - const inboxIssues = getInboxIssuesByInboxId(inboxId); - const issueStatus = (inboxIssueId && inboxId && getInboxIssueByIssueId(inboxId, inboxIssueId)) || undefined; - const issue = (inboxIssueId && getIssueById(inboxIssueId)) || undefined; - - const currentIssueIndex = inboxIssues?.findIndex((issue) => issue === inboxIssueId) ?? 0; - - const inboxIssueOperations: TInboxIssueOperations = useMemo( - () => ({ - updateInboxIssueStatus: async (data: TInboxDetailedStatus) => { - try { - if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId) throw new Error("Missing required parameters"); - await updateInboxIssueStatus(workspaceSlug, projectId, inboxId, inboxIssueId, data); - } catch (error) { - setToast({ - type: TOAST_TYPE.ERROR, - title: "Error!", - message: "Something went wrong while updating inbox status. Please try again.", - }); - } - }, - removeInboxIssue: async () => { - try { - if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId || !currentWorkspace) - throw new Error("Missing required parameters"); - await removeInboxIssue(workspaceSlug, projectId, inboxId, inboxIssueId); - captureIssueEvent({ - eventName: ISSUE_DELETED, - payload: { - id: inboxIssueId, - state: "SUCCESS", - element: "Inbox page", - }, - }); - router.push({ - pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`, - }); - } catch (error) { - setToast({ - type: TOAST_TYPE.ERROR, - title: "Error!", - message: "Something went wrong while deleting inbox issue. Please try again.", - }); - captureIssueEvent({ - eventName: ISSUE_DELETED, - payload: { - id: inboxIssueId, - state: "FAILED", - element: "Inbox page", - }, - }); - } - }, - }), - [ - currentWorkspace, - workspaceSlug, - projectId, - inboxId, - inboxIssueId, - updateInboxIssueStatus, - removeInboxIssue, - captureIssueEvent, - router, - ] - ); - - const handleInboxIssueNavigation = useCallback( - (direction: "next" | "prev") => { - if (!inboxIssues || !inboxIssueId) return; - const activeElement = document.activeElement as HTMLElement; - if (activeElement && (activeElement.classList.contains("tiptap") || activeElement.id === "title-input")) return; - const nextIssueIndex = - direction === "next" - ? (currentIssueIndex + 1) % inboxIssues.length - : (currentIssueIndex - 1 + inboxIssues.length) % inboxIssues.length; - const nextIssueId = inboxIssues[nextIssueIndex]; - if (!nextIssueId) return; - router.push({ - pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`, - query: { - inboxIssueId: nextIssueId, - }, - }); - }, - [workspaceSlug, projectId, inboxId, inboxIssues, inboxIssueId, currentIssueIndex, router] - ); - - const onKeyDown = useCallback( - (e: KeyboardEvent) => { - if (e.key === "ArrowUp") { - handleInboxIssueNavigation("prev"); - } else if (e.key === "ArrowDown") { - handleInboxIssueNavigation("next"); - } - }, - [handleInboxIssueNavigation] - ); - - useEffect(() => { - document.addEventListener("keydown", onKeyDown); - - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [onKeyDown]); - - const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; - - const today = new Date(); - const tomorrow = getDate(today); - tomorrow?.setDate(today.getDate() + 1); - useEffect(() => { - if (!issueStatus || !issueStatus.snoozed_till) return; - setDate(issueStatus.snoozed_till); - }, [issueStatus]); - - if (!issueStatus || !issue || !inboxIssues) return <>; - return ( - <> - {issue && ( - <> - setSelectDuplicateIssue(false)} - value={issueStatus.duplicate_to} - onSubmit={(dupIssueId) => { - inboxIssueOperations - .updateInboxIssueStatus({ - status: 2, - duplicate_to: dupIssueId, - }) - .finally(() => setSelectDuplicateIssue(false)); - }} - /> - - setAcceptIssueModal(false)} - onSubmit={async () => { - await inboxIssueOperations - .updateInboxIssueStatus({ - status: 1, - }) - .finally(() => setAcceptIssueModal(false)); - }} - /> - - setDeclineIssueModal(false)} - onSubmit={async () => { - await inboxIssueOperations - .updateInboxIssueStatus({ - status: -1, - }) - .finally(() => setDeclineIssueModal(false)); - }} - /> - - setDeleteIssueModal(false)} - onSubmit={async () => { - await inboxIssueOperations.removeInboxIssue().finally(() => setDeclineIssueModal(false)); - }} - /> - - )} - - {inboxIssueId && ( -
-
- - -
- {currentIssueIndex + 1}/{inboxIssues?.length ?? 0} -
-
- -
- {isAllowed && (issueStatus.status === 0 || issueStatus.status === -2) && ( -
- - - - - - {({ close }) => ( -
- { - if (!date) return; - setDate(date); - }} - mode="single" - className="border border-custom-border-200 rounded-md p-3" - disabled={ - tomorrow - ? [ - { - before: tomorrow, - }, - ] - : undefined - } - /> - -
- )} -
-
-
- )} - - {isAllowed && issueStatus.status === -2 && ( -
- -
- )} - - {isAllowed && (issueStatus.status === 0 || issueStatus.status === -2) && ( -
- -
- )} - - {isAllowed && issueStatus.status === -2 && ( -
- -
- )} - - {(isAllowed || currentUser?.id === issue?.created_by) && ( -
- -
- )} -
-
- )} - - ); -}); diff --git a/web/components/inbox/inbox-issue-status.tsx b/web/components/inbox/inbox-issue-status.tsx index 701feff6b..e230b02d5 100644 --- a/web/components/inbox/inbox-issue-status.tsx +++ b/web/components/inbox/inbox-issue-status.tsx @@ -1,56 +1,45 @@ import React from "react"; import { observer } from "mobx-react"; -// hooks -import { INBOX_STATUS } from "@/constants/inbox"; -import { useInboxIssues } from "@/hooks/store"; // constants +import { INBOX_STATUS } from "@/constants/inbox"; +// helpers +import { cn } from "@/helpers/common.helper"; +// store +import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store"; type Props = { - workspaceSlug: string; - projectId: string; - inboxId: string; - issueId: string; + inboxIssue: IInboxIssueStore; iconSize?: number; showDescription?: boolean; }; export const InboxIssueStatus: React.FC = observer((props) => { - const { workspaceSlug, projectId, inboxId, issueId, iconSize = 18, showDescription = false } = props; - // hooks - const { - issues: { getInboxIssueByIssueId }, - } = useInboxIssues(); - - const inboxIssueDetail = getInboxIssueByIssueId(inboxId, issueId); - if (!inboxIssueDetail) return <>; - - const inboxIssueStatusDetail = INBOX_STATUS.find((s) => s.status === inboxIssueDetail.status); + const { inboxIssue, iconSize = 16, showDescription = false } = props; + // derived values + const inboxIssueStatusDetail = INBOX_STATUS.find((s) => s.status === inboxIssue.status); if (!inboxIssueStatusDetail) return <>; - const isSnoozedDatePassed = - inboxIssueDetail.status === 0 && !!inboxIssueDetail.snoozed_till && inboxIssueDetail.snoozed_till < new Date(); + const isSnoozedDatePassed = inboxIssue.status === 0 && new Date(inboxIssue.snoozed_till ?? "") < new Date(); + + const description = inboxIssueStatusDetail.description(new Date(inboxIssue.snoozed_till ?? "")); return (
- - {showDescription ? ( - inboxIssueStatusDetail.description( - workspaceSlug, - projectId, - inboxIssueDetail.duplicate_to ?? "", - inboxIssueDetail.snoozed_till - ) - ) : ( - {inboxIssueStatusDetail.title} + className={cn( + `relative flex flex-col gap-1 p-1.5 py-0.5 rounded ${inboxIssueStatusDetail.textColor( + isSnoozedDatePassed + )} ${inboxIssueStatusDetail.bgColor(isSnoozedDatePassed)}` )} + > +
+ +
+ {inboxIssue?.status === 0 && inboxIssue?.snoozed_till + ? inboxIssueStatusDetail.description(inboxIssue?.snoozed_till) + : inboxIssueStatusDetail.title} +
+
+ {showDescription &&
{description}
}
); }); diff --git a/web/components/inbox/index.ts b/web/components/inbox/index.ts index bc8be5506..8b05b565f 100644 --- a/web/components/inbox/index.ts +++ b/web/components/inbox/index.ts @@ -1,14 +1,6 @@ +export * from "./root"; export * from "./modals"; - -export * from "./inbox-issue-actions"; +export * from "./sidebar"; +export * from "./inbox-filter"; +export * from "./content"; export * from "./inbox-issue-status"; - -export * from "./content/root"; - -export * from "./sidebar/root"; - -export * from "./sidebar/filter/filter-selection"; -export * from "./sidebar/filter/applied-filters"; - -export * from "./sidebar/inbox-list"; -export * from "./sidebar/inbox-list-item"; diff --git a/web/components/inbox/modals/accept-issue-modal.tsx b/web/components/inbox/modals/accept-issue-modal.tsx index d8ccb68b6..080563505 100644 --- a/web/components/inbox/modals/accept-issue-modal.tsx +++ b/web/components/inbox/modals/accept-issue-modal.tsx @@ -5,11 +5,11 @@ import type { TIssue } from "@plane/types"; // icons // ui import { Button } from "@plane/ui"; -// types +// hooks import { useProject } from "@/hooks/store"; type Props = { - data: TIssue; + data: Partial; isOpen: boolean; onClose: () => void; onSubmit: () => Promise; @@ -70,7 +70,8 @@ export const AcceptIssueModal: React.FC = ({ isOpen, onClose, data, onSub

Are you sure you want to accept issue{" "} - {getProjectById(data?.project_id)?.identifier}-{data?.sequence_id} + {(data && data?.project_id && getProjectById(data?.project_id)?.identifier) || ""}- + {data?.sequence_id} {""}? Once accepted, this issue will be added to the project issues list.

diff --git a/web/components/inbox/modals/create-issue-modal.tsx b/web/components/inbox/modals/create-issue-modal.tsx index c32bcf8f4..4c22f8348 100644 --- a/web/components/inbox/modals/create-issue-modal.tsx +++ b/web/components/inbox/modals/create-issue-modal.tsx @@ -1,24 +1,24 @@ import { Fragment, useRef, useState } from "react"; -import { observer } from "mobx-react-lite"; +import { observer } from "mobx-react"; import { useRouter } from "next/router"; import { Controller, useForm } from "react-hook-form"; import { Sparkle } from "lucide-react"; -import { Dialog, Transition } from "@headlessui/react"; +import { Transition, Dialog } from "@headlessui/react"; import { RichTextEditorWithRef } from "@plane/rich-text-editor"; +// types import { TIssue } from "@plane/types"; -// hooks +// ui import { Button, Input, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui"; +// components import { GptAssistantPopover } from "@/components/core"; import { PriorityDropdown } from "@/components/dropdowns"; +// constants import { ISSUE_CREATED } from "@/constants/event-tracker"; -import { useApplication, useEventTracker, useWorkspace, useInboxIssues, useMention } from "@/hooks/store"; +// hooks +import { useApplication, useEventTracker, useWorkspace, useMention, useProjectInbox } from "@/hooks/store"; // services import { AIService } from "@/services/ai.service"; import { FileService } from "@/services/file.service"; -// components -// ui -// types -// constants type Props = { isOpen: boolean; @@ -26,10 +26,8 @@ type Props = { }; const defaultValues: Partial = { - project_id: "", name: "", description_html: "

", - parent_id: null, priority: "none", }; @@ -39,33 +37,27 @@ const fileService = new FileService(); export const CreateInboxIssueModal: React.FC = observer((props) => { const { isOpen, onClose } = props; + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + if (!workspaceSlug || !projectId) return null; // states const [createMore, setCreateMore] = useState(false); const [gptAssistantModal, setGptAssistantModal] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); // refs const editorRef = useRef(null); - // router - const router = useRouter(); - const { workspaceSlug, projectId, inboxId } = router.query as { - workspaceSlug: string; - projectId: string; - inboxId: string; - }; // hooks const { mentionHighlights, mentionSuggestions } = useMention(); const workspaceStore = useWorkspace(); const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; - // store hooks - const { - issues: { createInboxIssue }, - } = useInboxIssues(); + const { createInboxIssue } = useProjectInbox(); const { config: { envConfig }, } = useApplication(); const { captureIssueEvent } = useEventTracker(); - + // form info const { control, formState: { errors, isSubmitting }, @@ -73,24 +65,26 @@ export const CreateInboxIssueModal: React.FC = observer((props) => { reset, watch, getValues, - } = useForm({ defaultValues }); + } = useForm>({ defaultValues }); + const issueName = watch("name"); const handleClose = () => { onClose(); reset(defaultValues); + editorRef?.current?.clearEditor(); }; - const issueName = watch("name"); - const handleFormSubmit = async (formData: Partial) => { - if (!workspaceSlug || !projectId || !inboxId) return; - - await createInboxIssue(workspaceSlug.toString(), projectId.toString(), inboxId.toString(), formData) + if (!workspaceSlug || !projectId) return; + await createInboxIssue(workspaceSlug.toString(), projectId.toString(), formData) .then((res) => { if (!createMore) { - router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.id}`); + router.push(`/${workspaceSlug}/projects/${projectId}/inbox/?inboxIssueId=${res?.issue?.id}`); handleClose(); - } else reset(defaultValues); + } else { + reset(defaultValues); + editorRef?.current?.clearEditor(); + } captureIssueEvent({ eventName: ISSUE_CREATED, payload: { @@ -117,11 +111,11 @@ export const CreateInboxIssueModal: React.FC = observer((props) => { const handleAiAssistance = async (response: string) => { if (!workspaceSlug || !projectId) return; - editorRef.current?.setEditorValueAtCursorPosition(response); }; const handleAutoGenerateDescription = async () => { + const issueName = getValues("name"); if (!workspaceSlug || !projectId || !issueName) return; setIAmFeelingLucky(true); @@ -220,7 +214,7 @@ export const CreateInboxIssueModal: React.FC = observer((props) => {
- {issueName && issueName !== "" && ( + {watch("name") && issueName !== "" && ( +
+ + +
+ + + + ); +}; diff --git a/web/components/inbox/root.tsx b/web/components/inbox/root.tsx new file mode 100644 index 000000000..f74fd5780 --- /dev/null +++ b/web/components/inbox/root.tsx @@ -0,0 +1,68 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import useSWR from "swr"; +import { Inbox } from "lucide-react"; +// components +import { EmptyState } from "@/components/empty-state"; +import { InboxSidebar, InboxContentRoot } from "@/components/inbox"; +import { InboxLayoutLoader } from "@/components/ui"; +// constants +import { EmptyStateType } from "@/constants/empty-state"; +// hooks +import { useProjectInbox } from "@/hooks/store"; + +type TInboxIssueRoot = { + workspaceSlug: string; + projectId: string; + inboxIssueId: string | undefined; + inboxAccessible: boolean; +}; + +export const InboxIssueRoot: FC = observer((props) => { + const { workspaceSlug, projectId, inboxIssueId, inboxAccessible } = props; + // hooks + const { isLoading, error, fetchInboxIssues } = useProjectInbox(); + + useSWR( + inboxAccessible && workspaceSlug && projectId ? `PROJECT_INBOX_ISSUES_${workspaceSlug}_${projectId}` : null, + () => { + inboxAccessible && workspaceSlug && projectId && fetchInboxIssues(workspaceSlug.toString(), projectId.toString()); + }, + { revalidateOnFocus: false } + ); + + // loader + if (isLoading === "init-loading") + return ( +
+ +
+ ); + + // error + if (error && error?.status === "init-error") + return ( +
+ +
{error?.message}
+
+ ); + + return ( +
+ + + {inboxIssueId ? ( + + ) : ( +
+ +
+ )} +
+ ); +}); diff --git a/web/components/inbox/sidebar/filter/applied-filters.tsx b/web/components/inbox/sidebar/filter/applied-filters.tsx deleted file mode 100644 index 4569cf577..000000000 --- a/web/components/inbox/sidebar/filter/applied-filters.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { FC } from "react"; -import { observer } from "mobx-react-lite"; -// mobx store -// icons -import { X } from "lucide-react"; -import { TInboxIssueFilterOptions, TIssuePriorities } from "@plane/types"; -import { PriorityIcon } from "@plane/ui"; -// helpers -import { INBOX_STATUS } from "@/constants/inbox"; -import { replaceUnderscoreIfSnakeCase } from "@/helpers/string.helper"; -// types -import { useInboxIssues } from "@/hooks/store"; -// constants - -type TInboxIssueAppliedFilter = { workspaceSlug: string; projectId: string; inboxId: string }; - -export const IssueStatusLabel = ({ status }: { status: number }) => { - const issueStatusDetail = INBOX_STATUS.find((s) => s.status === status); - - if (!issueStatusDetail) return <>; - - return ( -
-
- -
-
{issueStatusDetail.title}
-
- ); -}; - -export const InboxIssueAppliedFilter: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId } = props; - // hooks - const { - filters: { inboxFilters, updateInboxFilters }, - } = useInboxIssues(); - - const filters = inboxFilters?.filters; - - const handleUpdateFilter = (filter: Partial) => { - if (!workspaceSlug || !projectId || !inboxId) return; - updateInboxFilters(workspaceSlug.toString(), projectId.toString(), inboxId.toString(), filter); - }; - - const handleClearAllFilters = () => { - const newFilters: TInboxIssueFilterOptions = { priority: [], inbox_status: [] }; - updateInboxFilters(workspaceSlug.toString(), projectId.toString(), inboxId.toString(), newFilters); - }; - - let filtersLength = 0; - Object.keys(filters ?? {}).forEach((key) => { - const filterKey = key as keyof TInboxIssueFilterOptions; - if (filters?.[filterKey] && Array.isArray(filters[filterKey])) filtersLength += (filters[filterKey] ?? []).length; - }); - - if (!filters || filtersLength <= 0) return <>; - return ( -
- {Object.keys(filters).map((key) => { - const filterKey = key as keyof TInboxIssueFilterOptions; - - if (filters[filterKey].length > 0) - return ( -
- {replaceUnderscoreIfSnakeCase(key)}: - {filters[filterKey]?.length < 0 ? ( - None - ) : ( -
- {filterKey === "priority" ? ( -
- {filters.priority?.map((priority) => ( -
-
-
- -
-
{priority}
-
- -
- ))} - -
- ) : filterKey === "inbox_status" ? ( -
- {filters.inbox_status?.map((status) => ( -
- - -
- ))} - -
- ) : ( - (filters[filterKey] as any)?.join(", ") - )} -
- )} -
- ); - })} - -
- ); -}); diff --git a/web/components/inbox/sidebar/filter/filter-selection.tsx b/web/components/inbox/sidebar/filter/filter-selection.tsx deleted file mode 100644 index fc9dc20eb..000000000 --- a/web/components/inbox/sidebar/filter/filter-selection.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { FC } from "react"; -import { observer } from "mobx-react-lite"; -import { useRouter } from "next/router"; -import { TInboxIssueFilterOptions } from "@plane/types"; -// mobx store -// ui -// icons -import { PriorityIcon } from "@plane/ui"; -import { MultiLevelDropdown } from "@/components/ui"; -// types -// constants -import { INBOX_STATUS } from "@/constants/inbox"; -import { ISSUE_PRIORITIES } from "@/constants/issue"; -import { useInboxIssues } from "@/hooks/store"; - -type TInboxIssueFilterSelection = { workspaceSlug: string; projectId: string; inboxId: string }; - -export const InboxIssueFilterSelection: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId } = props; - // router - const router = useRouter(); - const { inboxIssueId } = router.query; - // hooks - const { - filters: { inboxFilters, updateInboxFilters }, - } = useInboxIssues(); - - const filters = inboxFilters?.filters; - - let filtersLength = 0; - Object.keys(filters ?? {}).forEach((key) => { - const filterKey = key as keyof TInboxIssueFilterOptions; - if (filters?.[filterKey] && Array.isArray(filters[filterKey])) filtersLength += (filters[filterKey] ?? []).length; - }); - - return ( -
- { - if (!workspaceSlug || !projectId || !inboxId) return; - - const key = option.key as keyof TInboxIssueFilterOptions; - const currentValue: any[] = filters?.[key] ?? []; - - const valueExists = currentValue.includes(option.value); - - if (valueExists) - updateInboxFilters(workspaceSlug.toString(), projectId.toString(), inboxId.toString(), { - [option.key]: currentValue.filter((val) => val !== option.value), - }); - else - updateInboxFilters(workspaceSlug.toString(), projectId.toString(), inboxId.toString(), { - [option.key]: [...currentValue, option.value], - }); - - if (inboxIssueId) { - router.push({ - pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`, - }); - } - }} - direction="right" - height="rg" - options={[ - { - id: "priority", - label: "Priority", - value: ISSUE_PRIORITIES.map((p) => p.key), - hasChildren: true, - children: ISSUE_PRIORITIES.map((priority) => ({ - id: priority.key, - label: ( -
- {priority.title ?? "None"} -
- ), - value: { - key: "priority", - value: priority.key, - }, - selected: filters?.priority?.includes(priority.key), - })), - }, - { - id: "inbox_status", - label: "Status", - value: INBOX_STATUS.map((status) => status.status), - hasChildren: true, - children: INBOX_STATUS.map((status) => ({ - id: status.status.toString(), - label: ( -
-
- -
-
{status.title}
-
- ), - value: { - key: "inbox_status", - value: status.status, - }, - selected: filters?.inbox_status?.includes(status.status), - })), - }, - ]} - /> - - {filtersLength > 0 && ( -
- {filtersLength} -
- )} -
- ); -}); diff --git a/web/components/inbox/sidebar/inbox-list-item.tsx b/web/components/inbox/sidebar/inbox-list-item.tsx index 792ade860..262d1e6c0 100644 --- a/web/components/inbox/sidebar/inbox-list-item.tsx +++ b/web/components/inbox/sidebar/inbox-list-item.tsx @@ -1,49 +1,40 @@ -import { FC, useEffect } from "react"; +import { FC, MouseEvent, useEffect } from "react"; import { observer } from "mobx-react"; import Link from "next/link"; import { useRouter } from "next/router"; -// icons -import { CalendarDays } from "lucide-react"; -// hooks -// ui import { Tooltip, PriorityIcon } from "@plane/ui"; -// helpers -import { InboxIssueStatus } from "@/components/inbox/inbox-issue-status"; -import { renderFormattedDate } from "@/helpers/date-time.helper"; // components -import { useInboxIssues, useIssueDetail, useProject } from "@/hooks/store"; +import { InboxIssueStatus } from "@/components/inbox"; +// helpers +import { cn } from "@/helpers/common.helper"; +import { renderFormattedDate } from "@/helpers/date-time.helper"; +// hooks +import { useLabel } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; +// store +import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store"; -type TInboxIssueListItem = { +type InboxIssueListItemProps = { workspaceSlug: string; projectId: string; - inboxId: string; - issueId: string; + projectIdentifier?: string; + inboxIssue: IInboxIssueStore; }; -export const InboxIssueListItem: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId, issueId } = props; +export const InboxIssueListItem: FC = observer((props) => { + const { workspaceSlug, projectId, inboxIssue, projectIdentifier } = props; // router const router = useRouter(); const { inboxIssueId } = router.query; - // hooks - const { getProjectById } = useProject(); - const { - issues: { getInboxIssueByIssueId }, - } = useInboxIssues(); - const { - issue: { getIssueById }, - } = useIssueDetail(); + // store + const { projectLabels } = useLabel(); const { isMobile } = usePlatformOS(); - const inboxIssueDetail = getInboxIssueByIssueId(inboxId, issueId); - const issue = getIssueById(issueId); - - if (!issue || !inboxIssueDetail) return <>; + const issue = inboxIssue.issue; useEffect(() => { - if (issueId === inboxIssueId) { + if (issue.id === inboxIssueId) { setTimeout(() => { - const issueItemCard = document.getElementById(`inbox-issue-list-item-${issueId}`); + const issueItemCard = document.getElementById(`inbox-issue-list-item-${issue.id}`); if (issueItemCard) issueItemCard.scrollIntoView({ behavior: "smooth", @@ -51,52 +42,81 @@ export const InboxIssueListItem: FC = observer((props) => { }); }, 200); } - }, [issueId, inboxIssueId]); + }, [inboxIssueId, issue.id]); + const handleIssueRedirection = (event: MouseEvent, currentIssueId: string | undefined) => { + if (inboxIssueId === currentIssueId) event.preventDefault(); + }; + + if (!issue) return <>; return ( <> handleIssueRedirection(e, issue.id)} >
-
-
-

- {getProjectById(issue.project_id)?.identifier}-{issue.sequence_id} -

-
{issue.name}
-
-
- +
+
+
+ {projectIdentifier}-{issue.sequence_id} +
+ {inboxIssue.status !== -2 && }
+

{issue.name}

- - - -
- - {renderFormattedDate(issue.created_at ?? "")} -
+
{renderFormattedDate(issue.created_at ?? "")}
+ +
+ + {issue.priority && ( + + + + )} + + {issue.label_ids && issue.label_ids.length > 3 ? ( +
+ + {`${issue.label_ids.length} labels`} +
+ ) : ( + <> + {(issue.label_ids ?? []).map((labelId) => { + const labelDetails = projectLabels?.find((l) => l.id === labelId); + if (!labelDetails) return null; + return ( +
+ + {labelDetails.name} +
+ ); + })} + + )}
diff --git a/web/components/inbox/sidebar/inbox-list.tsx b/web/components/inbox/sidebar/inbox-list.tsx index 9d77f6baf..e6f536247 100644 --- a/web/components/inbox/sidebar/inbox-list.tsx +++ b/web/components/inbox/sidebar/inbox-list.tsx @@ -1,33 +1,33 @@ -import { FC } from "react"; +import { FC, Fragment } from "react"; import { observer } from "mobx-react"; -// hooks -import { useInboxIssues } from "@/hooks/store"; // components -import { InboxIssueListItem } from "../"; +import { InboxIssueListItem } from "@/components/inbox"; +// store +import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store"; -type TInboxIssueList = { workspaceSlug: string; projectId: string; inboxId: string }; +export type InboxIssueListProps = { + workspaceSlug: string; + projectId: string; + projectIdentifier?: string; + inboxIssues: IInboxIssueStore[]; +}; -export const InboxIssueList: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId } = props; - // hooks - const { - issues: { getInboxIssuesByInboxId }, - } = useInboxIssues(); +export const InboxIssueList: FC = observer((props) => { + const { workspaceSlug, projectId, projectIdentifier, inboxIssues } = props; - const inboxIssueIds = getInboxIssuesByInboxId(inboxId); - - if (!inboxIssueIds) return <>; return ( -
- {inboxIssueIds.map((issueId) => ( - + <> + {inboxIssues.map((inboxIssue) => ( + + + ))} -
+ ); }); diff --git a/web/components/inbox/sidebar/index.ts b/web/components/inbox/sidebar/index.ts new file mode 100644 index 000000000..8a7673423 --- /dev/null +++ b/web/components/inbox/sidebar/index.ts @@ -0,0 +1,3 @@ +export * from "./root"; +export * from "./inbox-list"; +export * from "./inbox-list-item"; diff --git a/web/components/inbox/sidebar/root.tsx b/web/components/inbox/sidebar/root.tsx index cedddba25..d1d08f017 100644 --- a/web/components/inbox/sidebar/root.tsx +++ b/web/components/inbox/sidebar/root.tsx @@ -1,49 +1,143 @@ -import { FC } from "react"; +import { FC, useCallback, useRef } from "react"; import { observer } from "mobx-react"; -import { Inbox } from "lucide-react"; -// hooks -import { InboxSidebarLoader } from "@/components/ui"; -import { useInboxIssues } from "@/hooks/store"; -// ui +import { useRouter } from "next/router"; +import { TInboxIssueCurrentTab } from "@plane/types"; +import { Loader } from "@plane/ui"; // components -import { InboxIssueList, InboxIssueFilterSelection, InboxIssueAppliedFilter } from "../"; +import { EmptyState } from "@/components/empty-state"; +import { FiltersRoot, InboxIssueAppliedFilters, InboxIssueList } from "@/components/inbox"; +import { InboxSidebarLoader } from "@/components/ui"; +// constants +import { EmptyStateType } from "@/constants/empty-state"; +// helpers +import { cn } from "@/helpers/common.helper"; +// hooks +import { useProject, useProjectInbox } from "@/hooks/store"; +import { useIntersectionObserver } from "@/hooks/use-intersection-observer"; -type TInboxSidebarRoot = { +type IInboxSidebarProps = { workspaceSlug: string; projectId: string; - inboxId: string; }; -export const InboxSidebarRoot: FC = observer((props) => { - const { workspaceSlug, projectId, inboxId } = props; - // store hooks - const { - issues: { loader }, - } = useInboxIssues(); +const tabNavigationOptions: { key: TInboxIssueCurrentTab; label: string }[] = [ + { + key: "open", + label: "Open", + }, + { + key: "closed", + label: "Closed", + }, +]; - if (loader === "init-loader") { - return ; - } +export const InboxSidebar: FC = observer((props) => { + const { workspaceSlug, projectId } = props; + // ref + const containerRef = useRef(null); + const elementRef = useRef(null); + // store + const { currentProjectDetails } = useProject(); + const { + currentTab, + handleCurrentTab, + isLoading, + inboxIssuesArray, + inboxIssuePaginationInfo, + fetchInboxPaginationIssues, + getAppliedFiltersCount, + } = useProjectInbox(); + + const router = useRouter(); + + const fetchNextPages = useCallback(() => { + if (!workspaceSlug || !projectId) return; + fetchInboxPaginationIssues(workspaceSlug.toString(), projectId.toString()); + }, [workspaceSlug, projectId, fetchInboxPaginationIssues]); + // page observer + useIntersectionObserver({ + containerRef, + elementRef, + callback: fetchNextPages, + rootMargin: "20%", + }); return ( -
-
-
-
- +
+
+
+ {tabNavigationOptions.map((option) => ( +
{ + if (currentTab != option?.key) handleCurrentTab(option?.key); + router.push(`/${workspaceSlug}/projects/${projectId}/inbox`); + }} + > +
{option?.label}
+ {option?.key === "open" && currentTab === option?.key && ( +
+ {inboxIssuePaginationInfo?.total_results || 0} +
+ )} +
+
+ ))} +
+
-
- -
-
-
- -
+ -
- + {isLoading && !inboxIssuePaginationInfo?.next_page_results ? ( + + ) : ( +
+ {inboxIssuesArray.length > 0 ? ( + + ) : ( +
+ 0 + ? EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE + : currentTab === "open" + ? EmptyStateType.INBOX_SIDEBAR_OPEN_TAB + : EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB + } + layout="screen-simple" + /> +
+ )} + +
+ {inboxIssuePaginationInfo?.next_page_results && ( + + + + + )} +
+
+ )}
); diff --git a/web/components/issues/index.ts b/web/components/issues/index.ts index d1695b722..96136ccfe 100644 --- a/web/components/issues/index.ts +++ b/web/components/issues/index.ts @@ -3,7 +3,8 @@ export * from "./issue-modal"; export * from "./delete-issue-modal"; export * from "./description-form"; export * from "./issue-layouts"; - +export * from "./description-input"; +export * from "./title-input"; export * from "./parent-issues-list-modal"; export * from "./label"; export * from "./confirm-issue-discard"; diff --git a/web/components/issues/issue-detail/inbox/index.ts b/web/components/issues/issue-detail/inbox/index.ts deleted file mode 100644 index 0c4adc7d0..000000000 --- a/web/components/issues/issue-detail/inbox/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./root"; -export * from "./main-content"; -export * from "./sidebar"; diff --git a/web/components/issues/issue-detail/inbox/main-content.tsx b/web/components/issues/issue-detail/inbox/main-content.tsx deleted file mode 100644 index 2bea576c4..000000000 --- a/web/components/issues/issue-detail/inbox/main-content.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useEffect, useState } from "react"; -import { observer } from "mobx-react-lite"; -// hooks -import { StateGroupIcon } from "@plane/ui"; -import { IssueUpdateStatus, TIssueOperations } from "@/components/issues"; -import { useIssueDetail, useProjectState, useUser } from "@/hooks/store"; -import useReloadConfirmations from "@/hooks/use-reload-confirmation"; -// components -import { InboxIssueStatus } from "../../../inbox/inbox-issue-status"; -import { IssueDescriptionInput } from "../../description-input"; -import { IssueTitleInput } from "../../title-input"; -import { IssueActivity } from "../issue-activity"; -import { IssueReaction } from "../reactions"; -// ui - -type Props = { - workspaceSlug: string; - projectId: string; - inboxId: string; - issueId: string; - issueOperations: TIssueOperations; - is_editable: boolean; -}; - -export const InboxIssueMainContent: React.FC = observer((props) => { - const { workspaceSlug, projectId, inboxId, issueId, issueOperations, is_editable } = props; - // states - const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); - // hooks - const { currentUser } = useUser(); - const { projectStates } = useProjectState(); - const { - issue: { getIssueById }, - } = useIssueDetail(); - const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting"); - - useEffect(() => { - if (isSubmitting === "submitted") { - setShowAlert(false); - setTimeout(async () => { - setIsSubmitting("saved"); - }, 3000); - } else if (isSubmitting === "submitting") { - setShowAlert(true); - } - }, [isSubmitting, setShowAlert, setIsSubmitting]); - - const issue = issueId ? getIssueById(issueId) : undefined; - if (!issue) return <>; - - const currentIssueState = projectStates?.find((s) => s.id === issue.state_id); - - const issueDescription = - issue.description_html !== undefined || issue.description_html !== null - ? issue.description_html != "" - ? issue.description_html - : "

" - : undefined; - - return ( - <> -
- - -
- {currentIssueState && ( - - )} - -
- - setIsSubmitting(value)} - issueOperations={issueOperations} - disabled={!is_editable} - value={issue.name} - /> - - setIsSubmitting(value)} - /> - - {currentUser && ( - - )} -
- -
- -
- - ); -}); diff --git a/web/components/issues/issue-detail/inbox/root.tsx b/web/components/issues/issue-detail/inbox/root.tsx deleted file mode 100644 index bab406d1f..000000000 --- a/web/components/issues/issue-detail/inbox/root.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { FC, useMemo } from "react"; -import { useRouter } from "next/router"; -import useSWR from "swr"; -import { TIssue } from "@plane/types"; -// components -import { TOAST_TYPE, setToast } from "@plane/ui"; -import { EUserProjectRoles } from "@/constants/project"; -import { useEventTracker, useInboxIssues, useIssueDetail, useUser } from "@/hooks/store"; -// ui -// types -import { TIssueOperations } from "../root"; -import { InboxIssueMainContent } from "./main-content"; -import { InboxIssueDetailsSidebar } from "./sidebar"; -// constants - -export type TInboxIssueDetailRoot = { - workspaceSlug: string; - projectId: string; - inboxId: string; - issueId: string; -}; - -export const InboxIssueDetailRoot: FC = (props) => { - const { workspaceSlug, projectId, inboxId, issueId } = props; - // router - const router = useRouter(); - // hooks - const { - issues: { fetchInboxIssueById, updateInboxIssue, removeInboxIssue }, - } = useInboxIssues(); - const { - issue: { getIssueById }, - fetchActivities, - fetchComments, - } = useIssueDetail(); - const { captureIssueEvent } = useEventTracker(); - const { - membership: { currentProjectRole }, - } = useUser(); - - const issueOperations: TIssueOperations = useMemo( - () => ({ - fetch: async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - await fetchInboxIssueById(workspaceSlug, projectId, inboxId, issueId); - } catch (error) { - console.error("Error fetching the parent issue"); - } - }, - update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => { - try { - await updateInboxIssue(workspaceSlug, projectId, inboxId, issueId, data); - captureIssueEvent({ - eventName: "Inbox issue updated", - payload: { ...data, state: "SUCCESS", element: "Inbox" }, - updates: { - changed_property: Object.keys(data).join(","), - change_details: Object.values(data).join(","), - }, - path: router.asPath, - }); - } catch (error) { - setToast({ - title: "Issue update failed", - type: TOAST_TYPE.ERROR, - message: "Issue update failed", - }); - captureIssueEvent({ - eventName: "Inbox issue updated", - payload: { state: "SUCCESS", element: "Inbox" }, - updates: { - changed_property: Object.keys(data).join(","), - change_details: Object.values(data).join(","), - }, - path: router.asPath, - }); - } - }, - remove: async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - await removeInboxIssue(workspaceSlug, projectId, inboxId, issueId); - setToast({ - title: "Issue deleted successfully", - type: TOAST_TYPE.SUCCESS, - message: "Issue deleted successfully", - }); - captureIssueEvent({ - eventName: "Inbox issue deleted", - payload: { id: issueId, state: "SUCCESS", element: "Inbox" }, - path: router.asPath, - }); - } catch (error) { - captureIssueEvent({ - eventName: "Inbox issue deleted", - payload: { id: issueId, state: "FAILED", element: "Inbox" }, - path: router.asPath, - }); - setToast({ - title: "Issue delete failed", - type: TOAST_TYPE.ERROR, - message: "Issue delete failed", - }); - } - }, - }), - [inboxId, fetchInboxIssueById, updateInboxIssue, removeInboxIssue] - ); - - useSWR( - workspaceSlug && projectId && inboxId && issueId - ? `INBOX_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${inboxId}_${issueId}` - : null, - async () => { - if (workspaceSlug && projectId && inboxId && issueId) { - await issueOperations.fetch(workspaceSlug, projectId, issueId); - await fetchActivities(workspaceSlug, projectId, issueId); - await fetchComments(workspaceSlug, projectId, issueId); - } - } - ); - - // checking if issue is editable, based on user role - const is_editable = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; - - // issue details - const issue = getIssueById(issueId); - - if (!issue) return <>; - return ( -
-
- -
-
- -
-
- ); -}; diff --git a/web/components/issues/issue-detail/index.ts b/web/components/issues/issue-detail/index.ts index 63ef560a1..dc36d97ab 100644 --- a/web/components/issues/issue-detail/index.ts +++ b/web/components/issues/issue-detail/index.ts @@ -1,14 +1,14 @@ export * from "./root"; - export * from "./main-content"; export * from "./sidebar"; - -// select -export * from "./cycle-select"; -export * from "./module-select"; -export * from "./parent-select"; -export * from "./relation-select"; export * from "./parent"; export * from "./label"; export * from "./subscription"; export * from "./links"; +export * from "./issue-activity"; +export * from "./reactions"; +// select components +export * from "./cycle-select"; +export * from "./module-select"; +export * from "./parent-select"; +export * from "./relation-select"; diff --git a/web/components/issues/issue-detail/label/create-label.tsx b/web/components/issues/issue-detail/label/create-label.tsx index de376ce79..cbdb441e4 100644 --- a/web/components/issues/issue-detail/label/create-label.tsx +++ b/web/components/issues/issue-detail/label/create-label.tsx @@ -7,7 +7,6 @@ import { Popover } from "@headlessui/react"; import { IIssueLabel } from "@plane/types"; // hooks import { Input, TOAST_TYPE, setToast } from "@plane/ui"; -import { useIssueDetail } from "@/hooks/store"; // ui // types import { TLabelOperations } from "./root"; @@ -16,6 +15,7 @@ type ILabelCreate = { workspaceSlug: string; projectId: string; issueId: string; + values: string[]; labelOperations: TLabelOperations; disabled?: boolean; }; @@ -26,11 +26,7 @@ const defaultValues: Partial = { }; export const LabelCreate: FC = (props) => { - const { workspaceSlug, projectId, issueId, labelOperations, disabled = false } = props; - // hooks - const { - issue: { getIssueById }, - } = useIssueDetail(); + const { workspaceSlug, projectId, issueId, values, labelOperations, disabled = false } = props; // state const [isCreateToggle, setIsCreateToggle] = useState(false); const handleIsCreateToggle = () => setIsCreateToggle(!isCreateToggle); @@ -70,9 +66,8 @@ export const LabelCreate: FC = (props) => { if (!workspaceSlug || !projectId || isSubmitting) return; try { - const issue = getIssueById(issueId); const labelResponse = await labelOperations.createLabel(workspaceSlug, projectId, formData); - const currentLabels = [...(issue?.label_ids || []), labelResponse.id]; + const currentLabels = [...(values || []), labelResponse.id]; await labelOperations.updateIssue(workspaceSlug, projectId, issueId, { label_ids: currentLabels }); reset(defaultValues); } catch (error) { diff --git a/web/components/issues/issue-detail/label/label-list-item.tsx b/web/components/issues/issue-detail/label/label-list-item.tsx index 2bb6d30d1..8dbd980c5 100644 --- a/web/components/issues/issue-detail/label/label-list-item.tsx +++ b/web/components/issues/issue-detail/label/label-list-item.tsx @@ -1,7 +1,7 @@ import { FC } from "react"; import { X } from "lucide-react"; // types -import { useIssueDetail, useLabel } from "@/hooks/store"; +import { useLabel } from "@/hooks/store"; import { TLabelOperations } from "./root"; type TLabelListItem = { @@ -9,24 +9,21 @@ type TLabelListItem = { projectId: string; issueId: string; labelId: string; + values: string[]; labelOperations: TLabelOperations; disabled: boolean; }; export const LabelListItem: FC = (props) => { - const { workspaceSlug, projectId, issueId, labelId, labelOperations, disabled } = props; + const { workspaceSlug, projectId, issueId, labelId, values, labelOperations, disabled } = props; // hooks - const { - issue: { getIssueById }, - } = useIssueDetail(); const { getLabelById } = useLabel(); - const issue = getIssueById(issueId); const label = getLabelById(labelId); const handleLabel = async () => { - if (issue && !disabled) { - const currentLabels = issue.label_ids.filter((_labelId) => _labelId !== labelId); + if (values && !disabled) { + const currentLabels = values.filter((_labelId) => _labelId !== labelId); await labelOperations.updateIssue(workspaceSlug, projectId, issueId, { label_ids: currentLabels }); } }; diff --git a/web/components/issues/issue-detail/label/label-list.tsx b/web/components/issues/issue-detail/label/label-list.tsx index 07ba72766..e6ec6e05c 100644 --- a/web/components/issues/issue-detail/label/label-list.tsx +++ b/web/components/issues/issue-detail/label/label-list.tsx @@ -1,9 +1,7 @@ import { FC } from "react"; import { observer } from "mobx-react"; // components -import { useIssueDetail } from "@/hooks/store"; import { LabelListItem } from "./label-list-item"; -// hooks // types import { TLabelOperations } from "./root"; @@ -11,21 +9,16 @@ type TLabelList = { workspaceSlug: string; projectId: string; issueId: string; + values: string[]; labelOperations: TLabelOperations; disabled: boolean; }; export const LabelList: FC = observer((props) => { - const { workspaceSlug, projectId, issueId, labelOperations, disabled } = props; - // hooks - const { - issue: { getIssueById }, - } = useIssueDetail(); + const { workspaceSlug, projectId, issueId, values, labelOperations, disabled } = props; + const issueLabels = values || undefined; - const issue = getIssueById(issueId); - const issueLabels = issue?.label_ids || undefined; - - if (!issue || !issueLabels) return <>; + if (!issueId || !issueLabels) return <>; return ( <> {issueLabels.map((labelId) => ( @@ -35,6 +28,7 @@ export const LabelList: FC = observer((props) => { projectId={projectId} issueId={issueId} labelId={labelId} + values={issueLabels} labelOperations={labelOperations} disabled={disabled} /> diff --git a/web/components/issues/issue-detail/label/root.tsx b/web/components/issues/issue-detail/label/root.tsx index 6309ada64..31030555a 100644 --- a/web/components/issues/issue-detail/label/root.tsx +++ b/web/components/issues/issue-detail/label/root.tsx @@ -4,7 +4,7 @@ import { IIssueLabel, TIssue } from "@plane/types"; // components import { TOAST_TYPE, setToast } from "@plane/ui"; // hooks -import { useIssueDetail, useLabel } from "@/hooks/store"; +import { useIssueDetail, useLabel, useProjectInbox } from "@/hooks/store"; // ui // types import { LabelList, LabelCreate, IssueLabelSelectRoot } from "./"; @@ -28,6 +28,12 @@ export const IssueLabel: FC = observer((props) => { // hooks const { updateIssue } = useIssueDetail(); const { createLabel } = useLabel(); + const { + issue: { getIssueById }, + } = useIssueDetail(); + const { getIssueInboxByIssueId } = useProjectInbox(); + + const issue = isInboxIssue ? getIssueInboxByIssueId(issueId)?.issue : getIssueById(issueId); const labelOperations: TLabelOperations = useMemo( () => ({ @@ -72,6 +78,7 @@ export const IssueLabel: FC = observer((props) => { workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} + values={issue?.label_ids || []} labelOperations={labelOperations} disabled={disabled} /> @@ -81,6 +88,7 @@ export const IssueLabel: FC = observer((props) => { workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} + values={issue?.label_ids || []} labelOperations={labelOperations} /> )} @@ -90,6 +98,7 @@ export const IssueLabel: FC = observer((props) => { workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} + values={issue?.label_ids || []} labelOperations={labelOperations} /> )} diff --git a/web/components/issues/issue-detail/label/select/label-select.tsx b/web/components/issues/issue-detail/label/select/label-select.tsx index 2882a1e0e..814758ebc 100644 --- a/web/components/issues/issue-detail/label/select/label-select.tsx +++ b/web/components/issues/issue-detail/label/select/label-select.tsx @@ -4,22 +4,20 @@ import { usePopper } from "react-popper"; import { Check, Search, Tag } from "lucide-react"; import { Combobox } from "@headlessui/react"; // hooks -import { useIssueDetail, useLabel } from "@/hooks/store"; +import { useLabel } from "@/hooks/store"; // components export interface IIssueLabelSelect { workspaceSlug: string; projectId: string; issueId: string; + values: string[]; onSelect: (_labelIds: string[]) => void; } export const IssueLabelSelect: React.FC = observer((props) => { - const { workspaceSlug, projectId, issueId, onSelect } = props; + const { workspaceSlug, projectId, issueId, values, onSelect } = props; // store hooks - const { - issue: { getIssueById }, - } = useIssueDetail(); const { fetchProjectLabels, getProjectLabels } = useLabel(); // states const [referenceElement, setReferenceElement] = useState(null); @@ -27,7 +25,6 @@ export const IssueLabelSelect: React.FC = observer((props) => const [isLoading, setIsLoading] = useState(false); const [query, setQuery] = useState(""); - const issue = getIssueById(issueId); const projectLabels = getProjectLabels(projectId); const fetchLabels = () => { @@ -67,7 +64,7 @@ export const IssueLabelSelect: React.FC = observer((props) => ], }); - const issueLabels = issue?.label_ids ?? []; + const issueLabels = values ?? []; const label = (
= observer((props) => } }; - if (!issue) return <>; + if (!issueId || !values) return <>; return ( <> diff --git a/web/components/issues/issue-detail/label/select/root.tsx b/web/components/issues/issue-detail/label/select/root.tsx index de0bcca90..00f96522b 100644 --- a/web/components/issues/issue-detail/label/select/root.tsx +++ b/web/components/issues/issue-detail/label/select/root.tsx @@ -8,17 +8,24 @@ type TIssueLabelSelectRoot = { workspaceSlug: string; projectId: string; issueId: string; + values: string[]; labelOperations: TLabelOperations; }; export const IssueLabelSelectRoot: FC = (props) => { - const { workspaceSlug, projectId, issueId, labelOperations } = props; + const { workspaceSlug, projectId, issueId, values, labelOperations } = props; const handleLabel = async (_labelIds: string[]) => { await labelOperations.updateIssue(workspaceSlug, projectId, issueId, { label_ids: _labelIds }); }; return ( - + ); }; diff --git a/web/components/project/sidebar-list-item.tsx b/web/components/project/sidebar-list-item.tsx index bb1d6ad17..5041e81c3 100644 --- a/web/components/project/sidebar-list-item.tsx +++ b/web/components/project/sidebar-list-item.tsx @@ -32,9 +32,8 @@ import { import { LeaveProjectModal, ProjectLogo, PublishProjectModal } from "@/components/project"; import { EUserProjectRoles } from "@/constants/project"; import { cn } from "@/helpers/common.helper"; -import { getNumberCount } from "@/helpers/string.helper"; // hooks -import { useApplication, useEventTracker, useInbox, useProject } from "@/hooks/store"; +import { useApplication, useEventTracker, useProject } from "@/hooks/store"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; import { usePlatformOS } from "@/hooks/use-platform-os"; // helpers @@ -95,7 +94,6 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { const { theme: themeStore } = useApplication(); const { setTrackElement } = useEventTracker(); const { addProjectToFavorites, removeProjectFromFavorites, getProjectById } = useProject(); - const { getInboxesByProjectId, getInboxById } = useInbox(); const { isMobile } = usePlatformOS(); // states const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false); @@ -109,8 +107,6 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { // derived values const project = getProjectById(projectId); const isCollapsed = themeStore.sidebarCollapsed; - const inboxesMap = project?.inbox_view ? getInboxesByProjectId(projectId) : undefined; - const inboxDetails = inboxesMap && inboxesMap.length > 0 ? getInboxById(inboxesMap[0]) : undefined; // auth const isAdmin = project?.member_role === EUserProjectRoles.ADMIN; const isViewerOrGuest = @@ -375,36 +371,8 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { : "text-custom-sidebar-text-300 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80" } ${isCollapsed ? "justify-center" : ""}`} > - {item.name === "Inbox" && inboxDetails ? ( - <> -
- {inboxDetails?.pending_issue_count > 0 && ( - = 100, - }, - { - "border-none bg-custom-primary-300 text-white": router.asPath.includes( - item.href - ), - } - )} - > - {getNumberCount(inboxDetails?.pending_issue_count)} - - )} - -
- {!isCollapsed && item.name} - - ) : ( - <> - - {!isCollapsed && item.name} - - )} + + {!isCollapsed && item.name}
diff --git a/web/components/ui/loader/layouts/project-inbox/inbox-layout-loader.tsx b/web/components/ui/loader/layouts/project-inbox/inbox-layout-loader.tsx index 3456e43ab..095c0d543 100644 --- a/web/components/ui/loader/layouts/project-inbox/inbox-layout-loader.tsx +++ b/web/components/ui/loader/layouts/project-inbox/inbox-layout-loader.tsx @@ -4,22 +4,19 @@ import { Loader } from "@plane/ui"; import { InboxSidebarLoader } from "./inbox-sidebar-loader"; export const InboxLayoutLoader = () => ( -
- -
- -
+
+
+ +
+
+ +
-
- - - - -
+
diff --git a/web/components/ui/loader/layouts/project-inbox/inbox-sidebar-loader.tsx b/web/components/ui/loader/layouts/project-inbox/inbox-sidebar-loader.tsx index 204c2fff6..01da38f6a 100644 --- a/web/components/ui/loader/layouts/project-inbox/inbox-sidebar-loader.tsx +++ b/web/components/ui/loader/layouts/project-inbox/inbox-sidebar-loader.tsx @@ -1,24 +1,20 @@ import React from "react"; export const InboxSidebarLoader = () => ( -
-
- - -
-
- {[...Array(6)].map((i) => ( -
-
- - -
-
- - -
+
+ {[...Array(6)].map((i, index) => ( +
+
+ +
- ))} -
+
+ + + + +
+
+ ))}
); diff --git a/web/constants/empty-state.ts b/web/constants/empty-state.ts index 363147775..808b5470d 100644 --- a/web/constants/empty-state.ts +++ b/web/constants/empty-state.ts @@ -90,6 +90,13 @@ export enum EmptyStateType { ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE = "active-cycle-priority-issue-empty-state", ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE = "active-cycle-assignee-empty-state", ACTIVE_CYCLE_LABEL_EMPTY_STATE = "active-cycle-label-empty-state", + + DISABLED_PROJECT_INBOX = "disabled-project-inbox", + + INBOX_SIDEBAR_OPEN_TAB = "inbox-sidebar-open-tab", + INBOX_SIDEBAR_CLOSED_TAB = "inbox-sidebar-closed-tab", + INBOX_SIDEBAR_FILTER_EMPTY_STATE = "inbox-sidebar-filter-empty-state", + INBOX_DETAIL_EMPTY_STATE = "inbox-detail-empty-state", } const emptyStateDetails = { @@ -615,6 +622,41 @@ const emptyStateDetails = { title: "Add labels to issues to see the \n breakdown of work by labels.", path: "/empty-state/active-cycle/label", }, + [EmptyStateType.DISABLED_PROJECT_INBOX]: { + key: EmptyStateType.DISABLED_PROJECT_INBOX, + title: "Inbox is not enabled for the project.", + description: + "Inbox helps you manage incoming requests to your project and add them as issues in your workflow. Enable inbox \n from project settings to manage requests.", + accessType: "project", + access: EUserProjectRoles.ADMIN, + path: "/empty-state/disabled-feature/inbox", + primaryButton: { + text: "Manage features", + }, + }, + [EmptyStateType.INBOX_SIDEBAR_OPEN_TAB]: { + key: EmptyStateType.INBOX_SIDEBAR_OPEN_TAB, + title: "No open issues", + description: "Find open issues here. Create new issue.", + path: "/empty-state/inbox/inbox-issue", + }, + [EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB]: { + key: EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB, + title: "No closed issues", + description: "All the issues whether accepted or \n declined can be found here.", + path: "/empty-state/inbox/inbox-issue", + }, + [EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE]: { + key: EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE, + title: "No matching issues", + description: "No issue matches filter applied in inbox. \n Create a new issue.", + path: "/empty-state/inbox/filter-issue", + }, + [EmptyStateType.INBOX_DETAIL_EMPTY_STATE]: { + key: EmptyStateType.INBOX_DETAIL_EMPTY_STATE, + title: "Select an issue to view its details.", + path: "/empty-state/inbox/issue-detail", + }, } as const; export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; diff --git a/web/constants/inbox.tsx b/web/constants/inbox.tsx index b511b529e..6be3ad3fa 100644 --- a/web/constants/inbox.tsx +++ b/web/constants/inbox.tsx @@ -1,91 +1,90 @@ // icons -import { AlertTriangle, CheckCircle2, Clock, Copy, ExternalLink, LucideIcon, XCircle } from "lucide-react"; +import { AlertTriangle, CheckCircle2, Clock, Copy, LucideIcon, XCircle } from "lucide-react"; +// types +import { TInboxIssueSortingOrderByKeys, TInboxIssueSortingSortByKeys, TInboxIssueStatus } from "@plane/types"; // helpers -import { renderFormattedDate } from "@/helpers/date-time.helper"; +import { findHowManyDaysLeft } from "@/helpers/date-time.helper"; export const INBOX_STATUS: { key: string; - status: number; + status: TInboxIssueStatus; icon: LucideIcon; title: string; - description: ( - workspaceSlug: string, - projectId: string, - issueId: string, - snoozedTillDate: Date | undefined - ) => JSX.Element; + description: (snoozedTillDate: Date) => string; textColor: (snoozeDatePassed: boolean) => string; bgColor: (snoozeDatePassed: boolean) => string; - borderColor: (snoozeDatePassed: boolean) => string; }[] = [ { key: "pending", status: -2, icon: AlertTriangle, title: "Pending", - description: () =>

This issue is still pending.

, - textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-yellow-500"), - bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-yellow-500/10"), - borderColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "border-yellow-500"), + description: () => `Pending`, + textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-[#AB6400]"), + bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-[#FFF7C2]"), }, { key: "declined", status: -1, icon: XCircle, title: "Declined", - description: () =>

This issue has been declined.

, - textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-red-500"), - bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-red-500/10"), - borderColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "border-red-500"), + description: () => `Declined`, + textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-[#CE2C31]"), + bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-[#FEEBEC]"), }, { key: "snoozed", status: 0, icon: Clock, title: "Snoozed", - description: (workspaceSlug: string, projectId: string, issueId: string, snoozedTillDate: Date = new Date()) => - snoozedTillDate < new Date() ? ( -

This issue was snoozed till {renderFormattedDate(snoozedTillDate)}.

- ) : ( -

This issue has been snoozed till {renderFormattedDate(snoozedTillDate)}.

- ), - textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "text-red-500" : "text-custom-text-200"), - bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "bg-red-500/10" : "bg-gray-500/10"), - borderColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "border-red-500" : "border-gray-500"), + description: (snoozedTillDate: Date = new Date()) => `${findHowManyDaysLeft(snoozedTillDate)} days to go`, + textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "text-red-500" : "text-custom-text-400"), + bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "bg-red-500/10" : "bg-[#E0E1E6]"), }, { key: "accepted", status: 1, icon: CheckCircle2, title: "Accepted", - description: () =>

This issue has been accepted.

, - textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-green-500"), - bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-green-500/10"), - borderColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "border-green-500"), + description: () => `Accepted`, + textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-[#3E9B4F]"), + bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-[#E9F6E9]"), }, { key: "duplicate", status: 2, icon: Copy, title: "Duplicate", - description: (workspaceSlug: string, projectId: string, issueId: string) => ( -

- This issue has been marked as a duplicate of - - this issue - - . -

- ), + description: () => `Duplicate`, textColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "text-custom-text-200"), bgColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "bg-gray-500/10"), - borderColor: (snoozeDatePassed: boolean = false) => (snoozeDatePassed ? "" : "border-gray-500"), }, ]; export const INBOX_ISSUE_SOURCE = "in-app"; + +export const INBOX_ISSUE_ORDER_BY_OPTIONS: { key: TInboxIssueSortingOrderByKeys; label: string }[] = [ + { + key: "issue__created_at", + label: "Date created", + }, + { + key: "issue__updated_at", + label: "Date updated", + }, + { + key: "issue__sequence_id", + label: "ID", + }, +]; + +export const INBOX_ISSUE_SORT_BY_OPTIONS: { key: TInboxIssueSortingSortByKeys; label: string }[] = [ + { + key: "asc", + label: "Ascending", + }, + { + key: "desc", + label: "Descending", + }, +]; diff --git a/web/hooks/store/index.ts b/web/hooks/store/index.ts index 906b473ff..950ae00f1 100644 --- a/web/hooks/store/index.ts +++ b/web/hooks/store/index.ts @@ -23,5 +23,6 @@ export * from "./use-workspace"; export * from "./use-issues"; export * from "./use-kanban-view"; export * from "./use-issue-detail"; -export * from "./use-inbox"; +// project inbox +export * from "./use-project-inbox"; export * from "./use-inbox-issues"; diff --git a/web/hooks/store/use-inbox-issues.ts b/web/hooks/store/use-inbox-issues.ts index 000539e2c..f1afe751d 100644 --- a/web/hooks/store/use-inbox-issues.ts +++ b/web/hooks/store/use-inbox-issues.ts @@ -1,15 +1,9 @@ import { useContext } from "react"; // mobx store -import { StoreContext } from "@/contexts/store-context"; -// types -import { IInboxFilter } from "@/store/inbox/inbox_filter.store"; -import { IInboxIssue } from "@/store/inbox/inbox_issue.store"; +import { StoreContext } from "contexts/store-context"; -export const useInboxIssues = (): { - issues: IInboxIssue; - filters: IInboxFilter; -} => { +export const useInboxIssues = (inboxIssueId: string) => { const context = useContext(StoreContext); if (context === undefined) throw new Error("useInboxIssues must be used within StoreProvider"); - return { issues: context.inbox.inboxIssue, filters: context.inbox.inboxFilter }; + return context.projectInbox.getIssueInboxByIssueId(inboxIssueId) || {}; }; diff --git a/web/hooks/store/use-inbox.ts b/web/hooks/store/use-inbox.ts deleted file mode 100644 index d2a069834..000000000 --- a/web/hooks/store/use-inbox.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useContext } from "react"; -// mobx store -import { StoreContext } from "@/contexts/store-context"; -// types -import { IInbox } from "@/store/inbox/inbox.store"; - -export const useInbox = (): IInbox => { - const context = useContext(StoreContext); - if (context === undefined) throw new Error("useInbox must be used within StoreProvider"); - return context.inbox.inbox; -}; diff --git a/web/hooks/store/use-project-inbox.ts b/web/hooks/store/use-project-inbox.ts new file mode 100644 index 000000000..5da2c8161 --- /dev/null +++ b/web/hooks/store/use-project-inbox.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +// mobx store +import { StoreContext } from "contexts/store-context"; +// types +import { IProjectInboxStore } from "@/store/inbox/project-inbox.store"; + +export const useProjectInbox = (): IProjectInboxStore => { + const context = useContext(StoreContext); + if (context === undefined) throw new Error("useProjectInbox must be used within StoreProvider"); + return context.projectInbox; +}; diff --git a/web/hooks/use-intersection-observer.tsx b/web/hooks/use-intersection-observer.tsx new file mode 100644 index 000000000..eb57e58af --- /dev/null +++ b/web/hooks/use-intersection-observer.tsx @@ -0,0 +1,42 @@ +import { RefObject, useState, useEffect } from "react"; + +export type UseIntersectionObserverProps = { + containerRef: RefObject; + elementRef: RefObject; + callback: () => void; + rootMargin?: string; +}; + +export const useIntersectionObserver = (props: UseIntersectionObserverProps) => { + const { containerRef, elementRef, callback, rootMargin = "0px" } = props; + const [isVisible, setVisibility] = useState(false); + + useEffect(() => { + if (elementRef.current) { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + callback(); + } + setVisibility(entry.isIntersecting); + }, + { + root: containerRef.current, + rootMargin, + } + ); + observer.observe(elementRef.current); + return () => { + if (elementRef.current) { + // eslint-disable-next-line react-hooks/exhaustive-deps + observer.unobserve(elementRef.current); + } + }; + } + // while removing the current from the refs, the observer is not not working as expected + // fix this eslint warning with caution + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [rootMargin, callback, elementRef.current, containerRef.current]); + + return isVisible; +}; diff --git a/web/layouts/auth-layout/project-wrapper.tsx b/web/layouts/auth-layout/project-wrapper.tsx index 58084b0d4..5f4573360 100644 --- a/web/layouts/auth-layout/project-wrapper.tsx +++ b/web/layouts/auth-layout/project-wrapper.tsx @@ -19,7 +19,7 @@ import { useProjectState, useProjectView, useUser, - useInbox, + // useInbox, } from "@/hooks/store"; // images import emptyProject from "public/empty-state/project.svg"; @@ -31,7 +31,7 @@ interface IProjectAuthWrapper { export const ProjectAuthWrapper: FC = observer((props) => { const { children } = props; // store - const { fetchInboxes } = useInbox(); + // const { fetchInboxes } = useInbox(); const { commandPalette: { toggleCreateProjectModal }, } = useApplication(); @@ -39,7 +39,7 @@ export const ProjectAuthWrapper: FC = observer((props) => { const { membership: { fetchUserProjectInfo, projectMemberInfo, hasPermissionToProject }, } = useUser(); - const { getProjectById, fetchProjectDetails, currentProjectDetails } = useProject(); + const { getProjectById, fetchProjectDetails } = useProject(); const { fetchAllCycles } = useCycle(); const { fetchModules } = useModule(); const { fetchViews } = useProjectView(); @@ -105,20 +105,6 @@ export const ProjectAuthWrapper: FC = observer((props) => { workspaceSlug && projectId ? () => fetchViews(workspaceSlug.toString(), projectId.toString()) : null, { revalidateIfStale: false, revalidateOnFocus: false } ); - // fetching project inboxes if inbox is enabled in project settings - useSWR( - workspaceSlug && projectId && currentProjectDetails && currentProjectDetails.inbox_view - ? `PROJECT_INBOXES_${workspaceSlug}_${projectId}` - : null, - workspaceSlug && projectId && currentProjectDetails && currentProjectDetails.inbox_view - ? () => fetchInboxes(workspaceSlug.toString(), projectId.toString()) - : null, - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - } - ); - const projectExists = projectId ? getProjectById(projectId.toString()) : null; // check if the project member apis is loading diff --git a/web/next-env.d.ts b/web/next-env.d.ts index fd36f9494..4f11a03dc 100644 --- a/web/next-env.d.ts +++ b/web/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx deleted file mode 100644 index 03b1cc963..000000000 --- a/web/pages/[workspaceSlug]/projects/[projectId]/inbox/[inboxId].tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { ReactElement } from "react"; -import { observer } from "mobx-react"; -import { useRouter } from "next/router"; -import useSWR from "swr"; -// hooks -import { PageHead } from "@/components/core"; -import { ProjectInboxHeader } from "@/components/headers"; -import { InboxSidebarRoot, InboxContentRoot } from "@/components/inbox"; -import { InboxLayoutLoader } from "@/components/ui"; -import { useProject, useInboxIssues } from "@/hooks/store"; -// layouts -import { AppLayout } from "@/layouts/app-layout"; -// components -// types -import { NextPageWithLayout } from "@/lib/types"; - -const ProjectInboxPage: NextPageWithLayout = observer(() => { - const router = useRouter(); - const { workspaceSlug, projectId, inboxId, inboxIssueId } = router.query; - // store hooks - const { currentProjectDetails } = useProject(); - const { - filters: { fetchInboxFilters }, - issues: { fetchInboxIssues }, - } = useInboxIssues(); - // fetching the Inbox filters and issues - const { isLoading } = useSWR( - workspaceSlug && projectId && currentProjectDetails && currentProjectDetails?.inbox_view - ? `INBOX_ISSUES_${workspaceSlug.toString()}_${projectId.toString()}` - : null, - async () => { - if (workspaceSlug && projectId && inboxId && currentProjectDetails && currentProjectDetails?.inbox_view) { - await fetchInboxFilters(workspaceSlug.toString(), projectId.toString(), inboxId.toString()); - await fetchInboxIssues(workspaceSlug.toString(), projectId.toString(), inboxId.toString()); - } - } - ); - // derived values - const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Inbox` : undefined; - - if (!workspaceSlug || !projectId || !inboxId || !currentProjectDetails?.inbox_view || isLoading) - return ( -
- -
- ); - - return ( - <> - -
-
- -
-
- -
-
- - ); -}); - -ProjectInboxPage.getLayout = function getLayout(page: ReactElement) { - return ( - } withProjectWrapper> - {page} - - ); -}; - -export default ProjectInboxPage; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/inbox/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/inbox/index.tsx index 6f8bdda93..84205776f 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/inbox/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/inbox/index.tsx @@ -1,41 +1,54 @@ import { ReactElement } from "react"; import { observer } from "mobx-react"; import { useRouter } from "next/router"; -import useSWR from "swr"; -// hooks +// components +import { PageHead } from "@/components/core"; +import { EmptyState } from "@/components/empty-state"; import { ProjectInboxHeader } from "@/components/headers"; -import { InboxLayoutLoader } from "@/components/ui"; -import { useInbox, useProject } from "@/hooks/store"; +import { InboxIssueRoot } from "@/components/inbox"; +// constants +import { EmptyStateType } from "@/constants/empty-state"; +// hooks +import { useProject } from "@/hooks/store"; // layouts import { AppLayout } from "@/layouts/app-layout"; -// ui -// components // types import { NextPageWithLayout } from "@/lib/types"; const ProjectInboxPage: NextPageWithLayout = observer(() => { + /// router const router = useRouter(); - const { workspaceSlug, projectId } = router.query; - + const { workspaceSlug, projectId, inboxIssueId } = router.query; + // hooks const { currentProjectDetails } = useProject(); - const { fetchInboxes } = useInbox(); - useSWR( - workspaceSlug && projectId && currentProjectDetails && currentProjectDetails?.inbox_view - ? `INBOX_${workspaceSlug.toString()}_${projectId.toString()}` - : null, - async () => { - if (workspaceSlug && projectId && currentProjectDetails && currentProjectDetails?.inbox_view) { - const inboxes = await fetchInboxes(workspaceSlug.toString(), projectId.toString()); - if (inboxes && inboxes.length > 0) - router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxes[0].id}`); - } - } - ); + if (!workspaceSlug || !projectId) return <>; + + // No access to inbox + if (currentProjectDetails?.inbox_view === false) + return ( +
+ +
+ ); + + // derived values + const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Inbox` : "Plane - Inbox"; return (
- {currentProjectDetails?.inbox_view ? :
You don{"'"}t have access to inbox
} + +
+ +
); }); diff --git a/web/public/empty-state/disabled-feature/inbox-dark.webp b/web/public/empty-state/disabled-feature/inbox-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..d0e1055191029bc9d822e49b2e507fbb0c441a44 GIT binary patch literal 60900 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�C-ZC0x}lGc9u- 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
I^@0OT63lqX6wxp}?tgMynrS)s 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 A+yDRo literal 0 HcmV?d00001 diff --git a/web/public/empty-state/inbox/filter-issue-light.webp b/web/public/empty-state/inbox/filter-issue-light.webp new file mode 100644 index 0000000000000000000000000000000000000000..ba27009a69ff3651f09b9e0b77ea9b7345f07d7f GIT binary patch literal 40790 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 literal 0 HcmV?d00001 diff --git a/web/public/empty-state/inbox/inbox-issue-dark.webp b/web/public/empty-state/inbox/inbox-issue-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..4c15f9cdd0c89e93a8b975e44878c456cde3de2c GIT binary patch literal 40208 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≀l#s0wP2|gYD4Ed<{;UN3JeKou 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 literal 0 HcmV?d00001 diff --git a/web/public/empty-state/inbox/issue-detail-dark.webp b/web/public/empty-state/inbox/issue-detail-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..2a2c7063b259baa28e574ef2a858af2934a3cb9d GIT binary patch literal 2170 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 literal 0 HcmV?d00001 diff --git a/web/services/inbox.service.ts b/web/services/inbox.service.ts deleted file mode 100644 index b55c02870..000000000 --- a/web/services/inbox.service.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { API_BASE_URL } from "@/helpers/common.helper"; -import { APIService } from "@/services/api.service"; -// helpers -// types -import type { IInboxIssue, IInbox, TInboxStatus, IInboxQueryParams } from "@plane/types"; - -export class InboxService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async getInboxes(workspaceSlug: string, projectId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async getInboxById(workspaceSlug: string, projectId: string, inboxId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async patchInbox(workspaceSlug: string, projectId: string, inboxId: string, data: Partial): Promise { - return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async getInboxIssues( - workspaceSlug: string, - projectId: string, - inboxId: string, - params?: IInboxQueryParams - ): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, { - params, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async getInboxIssueById( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async deleteInboxIssue( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string - ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async markInboxStatus( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: TInboxStatus - ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, - data - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async patchInboxIssue( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: { issue: Partial } - ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, - data - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async createInboxIssue(workspaceSlug: string, projectId: string, inboxId: string, data: any): Promise { - return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/web/services/inbox/inbox-issue.service.ts b/web/services/inbox/inbox-issue.service.ts index 6bedf1256..f8fcf72c4 100644 --- a/web/services/inbox/inbox-issue.service.ts +++ b/web/services/inbox/inbox-issue.service.ts @@ -1,25 +1,27 @@ +// types +import type { TInboxIssue, TIssue, TInboxIssueWithPagination } from "@plane/types"; import { API_BASE_URL } from "@/helpers/common.helper"; import { APIService } from "@/services/api.service"; // helpers -// types -import type { TInboxIssueFilterOptions, TInboxIssueExtendedDetail, TIssue, TInboxDetailedStatus } from "@plane/types"; export class InboxIssueService extends APIService { constructor() { super(API_BASE_URL); } - async fetchInboxIssues( - workspaceSlug: string, - projectId: string, - inboxId: string, - params?: TInboxIssueFilterOptions | {} - ): Promise { + async list(workspaceSlug: string, projectId: string, params = {}): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieve(workspaceSlug: string, projectId: string, inboxIssueId: string): Promise { return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/?expand=issue_inbox`, - { - params, - } + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox` ) .then((response) => response?.data) .catch((error) => { @@ -27,83 +29,47 @@ export class InboxIssueService extends APIService { }); } - async fetchInboxIssueById( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox` - ) + async create(workspaceSlug: string, projectId: string, data: Partial): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/`, { + source: "IN_APP", + issue: data, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async createInboxIssue( + async update( workspaceSlug: string, projectId: string, - inboxId: string, - data: { - source: string; - issue: Partial; - } - ): Promise { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/?expand=issue_inbox`, - data - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async updateInboxIssue( - workspaceSlug: string, - projectId: string, - inboxId: string, inboxIssueId: string, - data: { issue: Partial } - ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox`, - data - ) + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async removeInboxIssue( + async updateIssue( workspaceSlug: string, projectId: string, - inboxId: string, - inboxIssueId: string - ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` - ) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async updateInboxIssueStatus( - workspaceSlug: string, - projectId: string, - inboxId: string, inboxIssueId: string, - data: TInboxDetailedStatus - ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/?expand=issue_inbox`, - data - ) + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`, { + issue: data, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async destroy(workspaceSlug: string, projectId: string, inboxIssueId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inbox-issues/${inboxIssueId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/web/services/inbox/inbox.service.ts b/web/services/inbox/inbox.service.ts deleted file mode 100644 index b14fcae21..000000000 --- a/web/services/inbox/inbox.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { API_BASE_URL } from "@/helpers/common.helper"; -import { APIService } from "@/services/api.service"; -// helpers -// types -import type { TInbox } from "@plane/types"; - -export class InboxService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async fetchInboxes(workspaceSlug: string, projectId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async fetchInboxById(workspaceSlug: string, projectId: string, inboxId: string): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async updateInbox(workspaceSlug: string, projectId: string, inboxId: string, data: Partial): Promise { - return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/web/services/inbox/index.ts b/web/services/inbox/index.ts index fe3f30fce..f4a25e361 100644 --- a/web/services/inbox/index.ts +++ b/web/services/inbox/index.ts @@ -1,2 +1 @@ -export * from "./inbox.service"; export * from "./inbox-issue.service"; diff --git a/web/store/inbox/inbox-issue.store.ts b/web/store/inbox/inbox-issue.store.ts new file mode 100644 index 000000000..1807645db --- /dev/null +++ b/web/store/inbox/inbox-issue.store.ts @@ -0,0 +1,139 @@ +import set from "lodash/set"; +import { makeObservable, observable, runInAction, action } from "mobx"; +// services +// types +import { TIssue, TInboxIssue, TInboxIssueStatus } from "@plane/types"; +import { InboxIssueService } from "@/services/inbox"; + +export interface IInboxIssueStore { + isLoading: boolean; + id: string; + status: TInboxIssueStatus; + issue: Partial; + snoozed_till: Date | undefined; + duplicate_to: string | undefined; + created_by: string | undefined; + // actions + updateInboxIssueStatus: (status: TInboxIssueStatus) => Promise; // accept, decline + updateInboxIssueDuplicateTo: (issueId: string) => Promise; // connecting the inbox issue to the project existing issue + updateInboxIssueSnoozeTill: (date: Date) => Promise; // snooze the issue + updateIssue: (issue: Partial) => Promise; // updating the issue +} + +export class InboxIssueStore implements IInboxIssueStore { + // observables + isLoading: boolean = false; + id: string; + status: TInboxIssueStatus = -2; + issue: Partial = {}; + snoozed_till: Date | undefined; + duplicate_to: string | undefined; + created_by: string | undefined; + workspaceSlug: string; + projectId: string; + // services + inboxIssueService; + + constructor(workspaceSlug: string, projectId: string, data: TInboxIssue) { + this.id = data.id; + this.status = data.status; + this.issue = data?.issue; + this.snoozed_till = data?.snoozed_till ? new Date(data.snoozed_till) : undefined; + this.duplicate_to = data?.duplicate_to || undefined; + this.created_by = data?.created_by || undefined; + this.workspaceSlug = workspaceSlug; + this.projectId = projectId; + // services + this.inboxIssueService = new InboxIssueService(); + // observable variables should be defined after the initialization of the values + makeObservable(this, { + id: observable, + status: observable, + issue: observable, + snoozed_till: observable, + duplicate_to: observable, + created_by: observable, + // actions + updateInboxIssueStatus: action, + updateInboxIssueDuplicateTo: action, + updateInboxIssueSnoozeTill: action, + updateIssue: action, + }); + } + + updateInboxIssueStatus = async (status: TInboxIssueStatus) => { + const previousData: Partial = { + status: this.status, + }; + try { + if (!this.issue.id) return; + set(this, "status", status); + await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, { + status: status, + }); + } catch { + runInAction(() => set(this, "status", previousData.status)); + } + }; + + updateInboxIssueDuplicateTo = async (issueId: string) => { + const inboxStatus = 2; + const previousData: Partial = { + status: this.status, + duplicate_to: this.duplicate_to, + }; + try { + if (!this.issue.id) return; + set(this, "status", inboxStatus); + set(this, "duplicate_to", issueId); + await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, { + status: inboxStatus, + duplicate_to: issueId, + }); + } catch { + runInAction(() => { + set(this, "status", previousData.status); + set(this, "duplicate_to", previousData.duplicate_to); + }); + } + }; + + updateInboxIssueSnoozeTill = async (date: Date) => { + const inboxStatus = 0; + const previousData: Partial = { + status: this.status, + snoozed_till: this.snoozed_till, + }; + try { + if (!this.issue.id) return; + set(this, "status", inboxStatus); + set(this, "snoozed_till", date); + await this.inboxIssueService.update(this.workspaceSlug, this.projectId, this.issue.id, { + status: inboxStatus, + snoozed_till: new Date(date), + }); + } catch { + runInAction(() => { + set(this, "status", previousData.status); + set(this, "snoozed_till", previousData.snoozed_till); + }); + } + }; + + updateIssue = async (issue: Partial) => { + const inboxIssue = this.issue; + try { + if (!this.issue.id) return; + Object.keys(issue).forEach((key) => { + const issueKey = key as keyof TIssue; + set(inboxIssue, issueKey, issue[issueKey]); + }); + await this.inboxIssueService.updateIssue(this.workspaceSlug, this.projectId, this.issue.id, issue); + } catch { + Object.keys(issue).forEach((key) => { + const issueKey = key as keyof TIssue; + set(inboxIssue, issueKey, inboxIssue[issueKey]); + }); + } + }; +} diff --git a/web/store/inbox/inbox.store.ts b/web/store/inbox/inbox.store.ts deleted file mode 100644 index 5d90b6d47..000000000 --- a/web/store/inbox/inbox.store.ts +++ /dev/null @@ -1,114 +0,0 @@ -import concat from "lodash/concat"; -import set from "lodash/set"; -import uniq from "lodash/uniq"; -import update from "lodash/update"; -import { observable, action, makeObservable, runInAction } from "mobx"; -import { computedFn } from "mobx-utils"; -// services -import { InboxService } from "@/services/inbox/inbox.service"; -// types -import { RootStore } from "@/store/root.store"; -import { TInboxDetailMap, TInboxDetailIdMap, TInbox } from "@plane/types"; - -export interface IInbox { - // observables - inboxes: TInboxDetailIdMap; - inboxMap: TInboxDetailMap; - // helper methods - getInboxesByProjectId: (projectId: string) => string[] | undefined; - getInboxById: (inboxId: string) => TInbox | undefined; - // fetch actions - fetchInboxes: (workspaceSlug: string, projectId: string) => Promise; - fetchInboxById: (workspaceSlug: string, projectId: string, inboxId: string) => Promise; - updateInbox: (workspaceSlug: string, projectId: string, inboxId: string, data: Partial) => Promise; -} - -export class Inbox implements IInbox { - // observables - inboxes: TInboxDetailIdMap = {}; - inboxMap: TInboxDetailMap = {}; - // root store - rootStore; - // services - inboxService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observables - inboxMap: observable, - inboxes: observable, - // actions - fetchInboxes: action, - fetchInboxById: action, - updateInbox: action, - }); - // root store - this.rootStore = _rootStore; - // services - this.inboxService = new InboxService(); - } - - // helper methods - getInboxesByProjectId = computedFn((projectId: string) => { - if (!projectId) return undefined; - return this.inboxes?.[projectId] ?? undefined; - }); - - getInboxById = computedFn((inboxId: string) => { - if (!inboxId) return undefined; - return this.inboxMap[inboxId] ?? undefined; - }); - - // actions - fetchInboxes = async (workspaceSlug: string, projectId: string) => { - try { - const response = await this.inboxService.fetchInboxes(workspaceSlug, projectId); - - const _inboxIds = response.map((inbox) => inbox.id); - runInAction(() => { - response.forEach((inbox) => { - set(this.inboxMap, inbox.id, inbox); - }); - set(this.inboxes, projectId, _inboxIds); - }); - - return response; - } catch (error) { - throw error; - } - }; - - fetchInboxById = async (workspaceSlug: string, projectId: string, inboxId: string) => { - try { - const response = await this.inboxService.fetchInboxById(workspaceSlug, projectId, inboxId); - - runInAction(() => { - set(this.inboxMap, inboxId, response); - update(this.inboxes, projectId, (inboxIds: string[] = []) => { - if (inboxIds.includes(inboxId)) return inboxIds; - return uniq(concat(inboxIds, inboxId)); - }); - }); - - return response; - } catch (error) { - throw error; - } - }; - - updateInbox = async (workspaceSlug: string, projectId: string, inboxId: string, data: Partial) => { - try { - const response = await this.inboxService.updateInbox(workspaceSlug, projectId, inboxId, data); - - runInAction(() => { - Object.keys(response).forEach((key) => { - set(this.inboxMap, [inboxId, key], response[key as keyof TInbox]); - }); - }); - - return response; - } catch (error) { - throw error; - } - }; -} diff --git a/web/store/inbox/inbox_filter.store.ts b/web/store/inbox/inbox_filter.store.ts deleted file mode 100644 index 603c75f9b..000000000 --- a/web/store/inbox/inbox_filter.store.ts +++ /dev/null @@ -1,129 +0,0 @@ -import isEmpty from "lodash/isEmpty"; -import set from "lodash/set"; -import { observable, action, makeObservable, runInAction, computed } from "mobx"; -// services -import { InboxService } from "@/services/inbox.service"; -// types -import { RootStore } from "@/store/root.store"; -import { TInboxIssueFilterOptions, TInboxIssueFilters, TInboxIssueQueryParams, TInbox } from "@plane/types"; - -export interface IInboxFilter { - // observables - filters: Record; // inbox_id -> TInboxIssueFilters - // computed - inboxFilters: TInboxIssueFilters | undefined; - inboxAppliedFilters: Partial> | undefined; - // actions - fetchInboxFilters: (workspaceSlug: string, projectId: string, inboxId: string) => Promise; - updateInboxFilters: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - filters: Partial - ) => Promise; -} - -export class InboxFilter implements IInboxFilter { - // observables - filters: Record = {}; - // root store - rootStore; - // services - inboxService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observables - filters: observable, - // computed - inboxFilters: computed, - inboxAppliedFilters: computed, - // actions - fetchInboxFilters: action, - updateInboxFilters: action, - }); - // root store - this.rootStore = _rootStore; - // services - this.inboxService = new InboxService(); - } - - get inboxFilters() { - const inboxId = this.rootStore.app.router.inboxId; - if (!inboxId) return undefined; - - const displayFilters = this.filters[inboxId] || undefined; - if (isEmpty(displayFilters)) return undefined; - - const _filters: TInboxIssueFilters = { - filters: { - priority: isEmpty(displayFilters?.filters?.priority) ? [] : displayFilters?.filters?.priority, - inbox_status: isEmpty(displayFilters?.filters?.inbox_status) ? [] : displayFilters?.filters?.inbox_status, - }, - }; - return _filters; - } - - get inboxAppliedFilters() { - const userFilters = this.inboxFilters; - if (!userFilters) return undefined; - - const filteredParams = { - priority: userFilters?.filters?.priority?.join(",") || undefined, - inbox_status: userFilters?.filters?.inbox_status?.join(",") || undefined, - }; - return filteredParams; - } - - fetchInboxFilters = async (workspaceSlug: string, projectId: string, inboxId: string) => { - try { - const response = await this.rootStore.inbox.inbox.fetchInboxById(workspaceSlug, projectId, inboxId); - - const filters: TInboxIssueFilterOptions = { - priority: response?.view_props?.filters?.priority || [], - inbox_status: response?.view_props?.filters?.inbox_status || [], - }; - - runInAction(() => { - set(this.filters, [inboxId], { filters: filters }); - }); - - return response; - } catch (error) { - throw error; - } - }; - - updateInboxFilters = async ( - workspaceSlug: string, - projectId: string, - inboxId: string, - filters: Partial - ) => { - try { - runInAction(() => { - Object.keys(filters).forEach((_key) => { - const _filterKey = _key as keyof TInboxIssueFilterOptions; - set(this.filters, [inboxId, "filters", _key], filters[_filterKey]); - }); - }); - - const inboxFilters = this.inboxFilters; - let _filters: TInboxIssueFilterOptions = { - priority: inboxFilters?.filters?.priority || [], - inbox_status: inboxFilters?.filters?.inbox_status || [], - }; - _filters = { ..._filters, ...filters }; - - this.rootStore.inbox.inboxIssue.fetchInboxIssues(workspaceSlug, projectId, inboxId, "mutation"); - - const response = await this.rootStore.inbox.inbox.updateInbox(workspaceSlug, projectId, inboxId, { - view_props: { filters: _filters }, - }); - - return response; - } catch (error) { - throw error; - } - }; -} diff --git a/web/store/inbox/inbox_issue.store.ts b/web/store/inbox/inbox_issue.store.ts deleted file mode 100644 index 6e5eb94f0..000000000 --- a/web/store/inbox/inbox_issue.store.ts +++ /dev/null @@ -1,267 +0,0 @@ -import concat from "lodash/concat"; -import pull from "lodash/pull"; -import set from "lodash/set"; -import uniq from "lodash/uniq"; -import update from "lodash/update"; -import { observable, action, makeObservable, runInAction } from "mobx"; -import { computedFn } from "mobx-utils"; -// services -import { InboxIssueService } from "@/services/inbox/inbox-issue.service"; -// types -import { RootStore } from "@/store/root.store"; -import type { - TInboxIssueDetailIdMap, - TInboxIssueDetailMap, - TInboxIssueDetail, - TInboxIssueExtendedDetail, - TInboxDetailedStatus, - TIssue, -} from "@plane/types"; - -type TLoader = "init-loader" | "mutation" | undefined; - -export interface IInboxIssue { - // observables - loader: TLoader; - inboxIssues: TInboxIssueDetailIdMap; - inboxIssueMap: TInboxIssueDetailMap; - // helper methods - getInboxIssuesByInboxId: (inboxId: string) => string[] | undefined; - getInboxIssueByIssueId: (inboxId: string, issueId: string) => TInboxIssueDetail | undefined; - // actions - fetchInboxIssues: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - loaderType?: TLoader - ) => Promise; - fetchInboxIssueById: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string - ) => Promise; - createInboxIssue: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - data: Partial - ) => Promise; - updateInboxIssue: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: Partial - ) => Promise; - removeInboxIssue: (workspaceSlug: string, projectId: string, inboxId: string, issueId: string) => Promise; - updateInboxIssueStatus: ( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: TInboxDetailedStatus - ) => Promise; -} - -export class InboxIssue implements IInboxIssue { - // observables - loader: TLoader = "init-loader"; - inboxIssues: TInboxIssueDetailIdMap = {}; - inboxIssueMap: TInboxIssueDetailMap = {}; - // root store - rootStore; - // services - inboxIssueService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observables - loader: observable.ref, - inboxIssues: observable, - inboxIssueMap: observable, - // actions - fetchInboxIssues: action, - fetchInboxIssueById: action, - createInboxIssue: action, - updateInboxIssue: action, - removeInboxIssue: action, - updateInboxIssueStatus: action, - }); - - // root store - this.rootStore = _rootStore; - // services - this.inboxIssueService = new InboxIssueService(); - } - - // helper methods - getInboxIssuesByInboxId = computedFn((inboxId: string) => { - if (!inboxId) return undefined; - return this.inboxIssues?.[inboxId] ?? undefined; - }); - - getInboxIssueByIssueId = computedFn((inboxId: string, issueId: string) => { - if (!inboxId) return undefined; - return this.inboxIssueMap?.[inboxId]?.[issueId] ?? undefined; - }); - - // actions - fetchInboxIssues = async ( - workspaceSlug: string, - projectId: string, - inboxId: string, - loaderType: TLoader = "init-loader" - ) => { - try { - this.loader = loaderType; - const queryParams = this.rootStore.inbox.inboxFilter.inboxAppliedFilters ?? {}; - - const response = await this.inboxIssueService.fetchInboxIssues(workspaceSlug, projectId, inboxId, queryParams); - - runInAction(() => { - response.forEach((_inboxIssue) => { - const { ["issue_inbox"]: issueInboxDetail, ...issue } = _inboxIssue; - this.rootStore.inbox.rootStore.issue.issues.addIssue([issue]); - const { ["id"]: omittedId, ...inboxIssue } = issueInboxDetail[0]; - set(this.inboxIssueMap, [inboxId, _inboxIssue.id], inboxIssue); - }); - }); - - const _inboxIssueIds = response.map((inboxIssue) => inboxIssue.id); - runInAction(() => { - set(this.inboxIssues, inboxId, _inboxIssueIds); - this.loader = undefined; - }); - - return response; - } catch (error) { - this.loader = undefined; - throw error; - } - }; - - fetchInboxIssueById = async (workspaceSlug: string, projectId: string, inboxId: string, inboxIssueId: string) => { - try { - const response = await this.inboxIssueService.fetchInboxIssueById( - workspaceSlug, - projectId, - inboxId, - inboxIssueId - ); - - runInAction(() => { - const { ["issue_inbox"]: issueInboxDetail, ...issue } = response; - this.rootStore.inbox.rootStore.issue.issues.updateIssue(issue.id, issue); - const { ["id"]: omittedId, ...inboxIssue } = issueInboxDetail[0]; - set(this.inboxIssueMap, [inboxId, response.id], inboxIssue); - }); - - runInAction(() => { - update(this.inboxIssues, inboxId, (inboxIssueIds: string[] = []) => { - if (inboxIssueIds.includes(response.id)) return inboxIssueIds; - return uniq(concat(inboxIssueIds, response.id)); - }); - }); - - // fetching issue activity - await this.rootStore.issue.issueDetail.fetchActivities(workspaceSlug, projectId, inboxIssueId); - // fetching issue reaction - await this.rootStore.issue.issueDetail.fetchReactions(workspaceSlug, projectId, inboxIssueId); - return response as any; - } catch (error) { - throw error; - } - }; - - createInboxIssue = async (workspaceSlug: string, projectId: string, inboxId: string, data: Partial) => { - try { - const response = await this.inboxIssueService.createInboxIssue(workspaceSlug, projectId, inboxId, { - source: "in-app", - issue: data, - }); - - runInAction(() => { - const { ["issue_inbox"]: issueInboxDetail, ...issue } = response; - this.rootStore.inbox.rootStore.issue.issues.addIssue([issue]); - const { ["id"]: omittedId, ...inboxIssue } = issueInboxDetail[0]; - set(this.inboxIssueMap, [inboxId, response.id], inboxIssue); - update(this.rootStore.inbox.inbox.inboxMap, [inboxId, "pending_issue_count"], (count: number = 0) => count + 1); - }); - - runInAction(() => { - update(this.inboxIssues, inboxId, (inboxIssueIds: string[] = []) => { - if (inboxIssueIds.includes(response.id)) return inboxIssueIds; - return uniq(concat(inboxIssueIds, response.id)); - }); - }); - - await this.rootStore.issue.issueDetail.fetchActivities(workspaceSlug, projectId, response.id); - return response; - } catch (error) { - throw error; - } - }; - - updateInboxIssue = async ( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: Partial - ) => { - try { - const response = await this.inboxIssueService.updateInboxIssue(workspaceSlug, projectId, inboxId, inboxIssueId, { - issue: data, - }); - - this.rootStore.inbox.rootStore.issue.issues.updateIssue(inboxIssueId, data); - - await this.rootStore.issue.issueDetail.fetchActivities(workspaceSlug, projectId, inboxIssueId); - } catch (error) { - throw error; - } - }; - - removeInboxIssue = async (workspaceSlug: string, projectId: string, inboxId: string, inboxIssueId: string) => { - try { - await this.inboxIssueService.removeInboxIssue(workspaceSlug, projectId, inboxId, inboxIssueId); - - runInAction(() => { - pull(this.inboxIssues[inboxId], inboxIssueId); - delete this.inboxIssueMap[inboxId][inboxIssueId]; - this.rootStore.inbox.rootStore.issue.issues.removeIssue(inboxIssueId); - update(this.rootStore.inbox.inbox.inboxMap, [inboxId, "pending_issue_count"], (count: number = 0) => count - 1); - }); - - await this.rootStore.issue.issueDetail.fetchActivities(workspaceSlug, projectId, inboxIssueId); - } catch (error) { - throw error; - } - }; - - updateInboxIssueStatus = async ( - workspaceSlug: string, - projectId: string, - inboxId: string, - inboxIssueId: string, - data: TInboxDetailedStatus - ) => { - try { - await this.inboxIssueService.updateInboxIssueStatus(workspaceSlug, projectId, inboxId, inboxIssueId, data); - - const pendingStatus = -2; - runInAction(() => { - set(this.inboxIssueMap, [inboxId, inboxIssueId, "status"], data.status); - - update(this.rootStore.inbox.inbox.inboxMap, [inboxId, "pending_issue_count"], (count: number = 0) => - data.status === pendingStatus ? count + 1 : count - 1 - ); - }); - - await this.rootStore.issue.issueDetail.fetchActivities(workspaceSlug, projectId, inboxIssueId); - } catch (error) { - throw error; - } - }; -} diff --git a/web/store/inbox/project-inbox.store.ts b/web/store/inbox/project-inbox.store.ts new file mode 100644 index 000000000..b871ccb98 --- /dev/null +++ b/web/store/inbox/project-inbox.store.ts @@ -0,0 +1,353 @@ +import isEmpty from "lodash/isEmpty"; +import omit from "lodash/omit"; +import set from "lodash/set"; +import { action, computed, makeObservable, observable, runInAction } from "mobx"; +import { computedFn } from "mobx-utils"; +// types +import { + TInboxIssue, + TInboxIssueCurrentTab, + TInboxIssueFilter, + TInboxIssueSorting, + TInboxIssuePaginationInfo, + TInboxIssueSortingOrderByQueryParam, +} from "@plane/types"; +// services +import { InboxIssueService } from "@/services/inbox"; +// root store +import { IInboxIssueStore, InboxIssueStore } from "@/store/inbox/inbox-issue.store"; +import { RootStore } from "@/store/root.store"; + +type TLoader = "init-loading" | "filter-loading" | "pagination-loading" | "issue-loading" | undefined; + +export interface IProjectInboxStore { + currentTab: TInboxIssueCurrentTab; + isLoading: TLoader; + error: { message: string; status: "init-error" | "pagination-error" } | undefined; + inboxFilters: Partial; + inboxSorting: Partial; + inboxIssuePaginationInfo: TInboxIssuePaginationInfo | undefined; + inboxIssues: Record; + // computed + getAppliedFiltersCount: number; + inboxIssuesArray: IInboxIssueStore[]; + // helper actions + getIssueInboxByIssueId: (issueId: string) => IInboxIssueStore | undefined; + inboxIssueQueryParams: ( + inboxFilters: Partial, + inboxSorting: Partial, + pagePerCount: number, + paginationCursor: string + ) => Partial>; + // actions + handleCurrentTab: (tab: TInboxIssueCurrentTab) => void; + handleInboxIssueFilters: (key: T, value: TInboxIssueFilter[T]) => void; // if user sends me undefined, I will remove the value from the filter key + handleInboxIssueSorting: (key: T, value: TInboxIssueSorting[T]) => void; // if user sends me undefined, I will remove the value from the filter key + fetchInboxIssues: (workspaceSlug: string, projectId: string, loadingType?: TLoader) => Promise; + fetchInboxPaginationIssues: (workspaceSlug: string, projectId: string) => Promise; + fetchInboxIssueById: (workspaceSlug: string, projectId: string, inboxIssueId: string) => Promise; + createInboxIssue: ( + workspaceSlug: string, + projectId: string, + data: Partial + ) => Promise; + deleteInboxIssue: (workspaceSlug: string, projectId: string, inboxIssueId: string) => Promise; +} + +export class ProjectInboxStore implements IProjectInboxStore { + // constants + PER_PAGE_COUNT = 10; + // observables + currentTab: TInboxIssueCurrentTab = "open"; + isLoading: TLoader = undefined; + error: { message: string; status: "init-error" | "pagination-error" } | undefined = undefined; + inboxFilters: Partial = { + status: [-2], + }; + inboxSorting: Partial = { + order_by: "issue__created_at", + sort_by: "desc", + }; + inboxIssuePaginationInfo: TInboxIssuePaginationInfo | undefined = undefined; + inboxIssues: Record = {}; + // services + inboxIssueService; + + constructor(private store: RootStore) { + makeObservable(this, { + currentTab: observable.ref, + isLoading: observable.ref, + inboxFilters: observable, + inboxSorting: observable, + inboxIssuePaginationInfo: observable, + inboxIssues: observable, + // computed + getAppliedFiltersCount: computed, + inboxIssuesArray: computed, + // actions + handleInboxIssueFilters: action, + handleInboxIssueSorting: action, + fetchInboxIssues: action, + fetchInboxPaginationIssues: action, + fetchInboxIssueById: action, + createInboxIssue: action, + deleteInboxIssue: action, + }); + this.inboxIssueService = new InboxIssueService(); + } + + // computed + get getAppliedFiltersCount() { + let count = 0; + this.inboxFilters != undefined && + Object.keys(this.inboxFilters).forEach((key) => { + const filterKey = key as keyof TInboxIssueFilter; + if (this.inboxFilters[filterKey] && this.inboxFilters?.[filterKey]) + count = count + (this.inboxFilters?.[filterKey]?.length ?? 0); + }); + return count; + } + + get inboxIssuesArray() { + return Object.values(this.inboxIssues || {}).filter((inbox) => + (this.currentTab === "open" ? [-2] : [-1, 0, 1, 2]).includes(inbox.status) + ); + } + + getIssueInboxByIssueId = computedFn((issueId: string) => this.inboxIssues?.[issueId] || undefined); + + inboxIssueQueryParams = ( + inboxFilters: Partial, + inboxSorting: Partial, + pagePerCount: number, + paginationCursor: string + ) => { + const filters: Partial> = {}; + !isEmpty(inboxFilters) && + Object.keys(inboxFilters).forEach((key) => { + const filterKey = key as keyof TInboxIssueFilter; + if (inboxFilters[filterKey] && inboxFilters[filterKey]?.length) + filters[filterKey] = inboxFilters[filterKey]?.join(","); + }); + + const sorting: TInboxIssueSortingOrderByQueryParam = { + order_by: "-issue__created_at", + }; + if (inboxSorting?.order_by && inboxSorting?.sort_by) { + switch (inboxSorting.order_by) { + case "issue__created_at": + if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__created_at`; + else sorting.order_by = "issue__created_at"; + break; + case "issue__updated_at": + if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__updated_at`; + else sorting.order_by = "issue__updated_at"; + break; + case "issue__sequence_id": + if (inboxSorting.sort_by === "desc") sorting.order_by = `-issue__sequence_id`; + else sorting.order_by = "issue__sequence_id"; + break; + default: + sorting.order_by = "-issue__created_at"; + break; + } + } + + return { + ...filters, + ...sorting, + per_page: pagePerCount, + cursor: paginationCursor, + }; + }; + + // actions + handleCurrentTab = (tab: TInboxIssueCurrentTab) => { + set(this, "currentTab", tab); + set(this, "inboxFilters", undefined); + set(this, ["inboxSorting", "order_by"], "issue__created_at"); + set(this, ["inboxSorting", "sort_by"], "desc"); + if (tab === "closed") set(this, ["inboxFilters", "status"], [-1, 0, 1, 2]); + else set(this, ["inboxFilters", "status"], [-2]); + const { workspaceSlug, projectId } = this.store.app.router; + if (workspaceSlug && projectId) this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading"); + }; + + handleInboxIssueFilters = (key: T, value: TInboxIssueFilter[T]) => { + set(this.inboxFilters, key, value); + const { workspaceSlug, projectId } = this.store.app.router; + if (workspaceSlug && projectId) this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading"); + }; + + handleInboxIssueSorting = (key: T, value: TInboxIssueSorting[T]) => { + set(this.inboxSorting, key, value); + const { workspaceSlug, projectId } = this.store.app.router; + if (workspaceSlug && projectId) this.fetchInboxIssues(workspaceSlug, projectId, "filter-loading"); + }; + + /** + * @description fetch inbox issues with paginated data + * @param workspaceSlug + * @param projectId + */ + fetchInboxIssues = async (workspaceSlug: string, projectId: string, loadingType: TLoader = undefined) => { + try { + if (loadingType) this.isLoading = loadingType; + else this.isLoading = "init-loading"; + this.inboxIssuePaginationInfo = undefined; + this.inboxIssues = {}; + + const queryParams = this.inboxIssueQueryParams( + this.inboxFilters, + this.inboxSorting, + this.PER_PAGE_COUNT, + `${this.PER_PAGE_COUNT}:0:0` + ); + const { results, ...paginationInfo } = await this.inboxIssueService.list(workspaceSlug, projectId, queryParams); + + runInAction(() => { + this.isLoading = undefined; + set(this, "inboxIssuePaginationInfo", paginationInfo); + if (results && results.length > 0) + results.forEach((value: TInboxIssue) => { + if (this.getIssueInboxByIssueId(value?.issue?.id) === undefined) + set(this.inboxIssues, value?.issue?.id, new InboxIssueStore(workspaceSlug, projectId, value)); + }); + }); + } catch (error) { + console.error("Error fetching the inbox issues", error); + this.isLoading = undefined; + this.error = { + message: "Error fetching the inbox issues please try again later.", + status: "init-error", + }; + throw error; + } + }; + + /** + * @description fetch inbox issues with paginated data + * @param workspaceSlug + * @param projectId + */ + fetchInboxPaginationIssues = async (workspaceSlug: string, projectId: string) => { + try { + if ( + !this.inboxIssuePaginationInfo?.total_results || + (this.inboxIssuePaginationInfo?.total_results && + this.inboxIssuesArray.length < this.inboxIssuePaginationInfo?.total_results) + ) { + this.isLoading = "pagination-loading"; + + const queryParams = this.inboxIssueQueryParams( + this.inboxFilters, + this.inboxSorting, + this.PER_PAGE_COUNT, + this.inboxIssuePaginationInfo?.next_cursor || `${this.PER_PAGE_COUNT}:0:0` + ); + const { results, ...paginationInfo } = await this.inboxIssueService.list(workspaceSlug, projectId, queryParams); + + runInAction(() => { + this.isLoading = undefined; + set(this, "inboxIssuePaginationInfo", paginationInfo); + if (results && results.length > 0) + results.forEach((value: TInboxIssue) => { + if (this.getIssueInboxByIssueId(value?.issue?.id) === undefined) + set(this.inboxIssues, value?.issue?.id, new InboxIssueStore(workspaceSlug, projectId, value)); + }); + }); + } else set(this, ["inboxIssuePaginationInfo", "next_page_results"], false); + } catch (error) { + console.error("Error fetching the inbox issues", error); + this.isLoading = undefined; + this.error = { + message: "Error fetching the paginated inbox issues please try again later.", + status: "pagination-error", + }; + throw error; + } + }; + + /** + * @description fetch inbox issue with issue id + * @param workspaceSlug + * @param projectId + * @param inboxIssueId + */ + fetchInboxIssueById = async (workspaceSlug: string, projectId: string, inboxIssueId: string) => { + try { + this.isLoading = "issue-loading"; + const inboxIssue = await this.inboxIssueService.retrieve(workspaceSlug, projectId, inboxIssueId); + const issueId = inboxIssue?.issue?.id || undefined; + + if (inboxIssue && issueId) { + // fetching reactions + await this.store.issue.issueDetail.fetchReactions(workspaceSlug, projectId, issueId); + // fetching activity + await this.store.issue.issueDetail.fetchReactions(workspaceSlug, projectId, issueId); + // fetching comments + await this.store.issue.issueDetail.fetchReactions(workspaceSlug, projectId, issueId); + runInAction(() => { + set(this.inboxIssues, issueId, new InboxIssueStore(workspaceSlug, projectId, inboxIssue)); + }); + this.isLoading = undefined; + } + } catch { + console.error("Error fetching the inbox issue with inbox issue id"); + this.isLoading = undefined; + } + }; + + /** + * @description create inbox issue + * @param workspaceSlug + * @param projectId + * @param data + */ + createInboxIssue = async (workspaceSlug: string, projectId: string, data: Partial) => { + try { + const inboxIssueResponse = await this.inboxIssueService.create(workspaceSlug, projectId, data); + if (inboxIssueResponse) + runInAction(() => { + set( + this.inboxIssues, + inboxIssueResponse?.issue?.id, + new InboxIssueStore(workspaceSlug, projectId, inboxIssueResponse) + ); + set( + this, + ["inboxIssuePaginationInfo", "total_results"], + (this.inboxIssuePaginationInfo?.total_results || 0) + 1 + ); + }); + return inboxIssueResponse; + } catch { + console.error("Error creating the inbox issue"); + } + }; + + /** + * @description delete inbox issue + * @param workspaceSlug + * @param projectId + * @param inboxIssueId + */ + deleteInboxIssue = async (workspaceSlug: string, projectId: string, inboxIssueId: string) => { + const currentIssue = this.inboxIssues?.[inboxIssueId]; + try { + if (!currentIssue) return; + runInAction(() => { + set( + this, + ["inboxIssuePaginationInfo", "total_results"], + (this.inboxIssuePaginationInfo?.total_results || 0) - 1 + ); + set(this, "inboxIssues", omit(this.inboxIssues, inboxIssueId)); + }); + await this.inboxIssueService.destroy(workspaceSlug, projectId, inboxIssueId); + } catch { + console.error("Error removing the inbox issue"); + set(this.inboxIssues, [inboxIssueId], currentIssue); + } + }; +} diff --git a/web/store/inbox/root.store.ts b/web/store/inbox/root.store.ts deleted file mode 100644 index 0628e28ab..000000000 --- a/web/store/inbox/root.store.ts +++ /dev/null @@ -1,26 +0,0 @@ -// types -import { RootStore } from "@/store/root.store"; -import { IInbox, Inbox } from "./inbox.store"; -import { IInboxFilter, InboxFilter } from "./inbox_filter.store"; -import { IInboxIssue, InboxIssue } from "./inbox_issue.store"; - -export interface IInboxRootStore { - rootStore: RootStore; - inbox: IInbox; - inboxIssue: IInboxIssue; - inboxFilter: IInboxFilter; -} - -export class InboxRootStore implements IInboxRootStore { - rootStore: RootStore; - inbox: IInbox; - inboxIssue: IInboxIssue; - inboxFilter: IInboxFilter; - - constructor(_rootStore: RootStore) { - this.rootStore = _rootStore; - this.inbox = new Inbox(_rootStore); - this.inboxIssue = new InboxIssue(_rootStore); - this.inboxFilter = new InboxFilter(_rootStore); - } -} diff --git a/web/store/issue/project/filter.store.ts b/web/store/issue/project/filter.store.ts index 707f8e705..66ce98344 100644 --- a/web/store/issue/project/filter.store.ts +++ b/web/store/issue/project/filter.store.ts @@ -71,9 +71,7 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj const displayFilters = this.filters[projectId] || undefined; if (isEmpty(displayFilters)) return undefined; - const _filters: IIssueFilters = this.computedIssueFilters(displayFilters); - - return _filters; + return this.computedIssueFilters(displayFilters); } get appliedFilters() { diff --git a/web/store/root.store.ts b/web/store/root.store.ts index 5dc3c2574..d0be5b452 100644 --- a/web/store/root.store.ts +++ b/web/store/root.store.ts @@ -1,25 +1,25 @@ import { enableStaticRendering } from "mobx-react-lite"; // root stores +import { ProjectInboxStore, IProjectInboxStore } from "@/store/inbox/project-inbox.store"; import { AppRootStore, IAppRootStore } from "./application"; import { CycleStore, ICycleStore } from "./cycle.store"; +import { CycleFilterStore, ICycleFilterStore } from "./cycle_filter.store"; import { DashboardStore, IDashboardStore } from "./dashboard.store"; import { IEstimateStore, EstimateStore } from "./estimate.store"; import { EventTrackerStore, IEventTrackerStore } from "./event-tracker.store"; import { GlobalViewStore, IGlobalViewStore } from "./global-view.store"; -import { IInboxRootStore, InboxRootStore } from "./inbox/root.store"; import { IssueRootStore, IIssueRootStore } from "./issue/root.store"; import { ILabelStore, LabelStore } from "./label.store"; import { IMemberRootStore, MemberRootStore } from "./member"; import { IMentionStore, MentionStore } from "./mention.store"; import { IModuleStore, ModulesStore } from "./module.store"; +import { IModuleFilterStore, ModuleFilterStore } from "./module_filter.store"; import { IProjectRootStore, ProjectRootStore } from "./project"; +import { IProjectPageStore, ProjectPageStore } from "./project-page.store"; import { IProjectViewStore, ProjectViewStore } from "./project-view.store"; import { IStateStore, StateStore } from "./state.store"; import { IUserRootStore, UserRootStore } from "./user"; import { IWorkspaceRootStore, WorkspaceRootStore } from "./workspace"; -import { IProjectPageStore, ProjectPageStore } from "./project-page.store"; -import { CycleFilterStore, ICycleFilterStore } from "./cycle_filter.store"; -import { IModuleFilterStore, ModuleFilterStore } from "./module_filter.store"; enableStaticRendering(typeof window === "undefined"); @@ -37,13 +37,13 @@ export class RootStore { projectView: IProjectViewStore; globalView: IGlobalViewStore; issue: IIssueRootStore; - inbox: IInboxRootStore; state: IStateStore; label: ILabelStore; estimate: IEstimateStore; mention: IMentionStore; dashboard: IDashboardStore; projectPages: IProjectPageStore; + projectInbox: IProjectInboxStore; constructor() { this.app = new AppRootStore(this); @@ -60,12 +60,13 @@ export class RootStore { this.projectView = new ProjectViewStore(this); this.globalView = new GlobalViewStore(this); this.issue = new IssueRootStore(this); - this.inbox = new InboxRootStore(this); this.state = new StateStore(this); this.label = new LabelStore(this); this.estimate = new EstimateStore(this); this.mention = new MentionStore(this); this.dashboard = new DashboardStore(this); + // inbox + this.projectInbox = new ProjectInboxStore(this); this.projectPages = new ProjectPageStore(this); } @@ -81,12 +82,12 @@ export class RootStore { this.projectView = new ProjectViewStore(this); this.globalView = new GlobalViewStore(this); this.issue = new IssueRootStore(this); - this.inbox = new InboxRootStore(this); this.state = new StateStore(this); this.label = new LabelStore(this); this.estimate = new EstimateStore(this); this.mention = new MentionStore(this); this.dashboard = new DashboardStore(this); + this.projectInbox = new ProjectInboxStore(this); this.projectPages = new ProjectPageStore(this); } }