From bf9049a7a2832cdc424d1136307c32bc87a49f0f Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Wed, 17 Apr 2024 19:43:22 +0530 Subject: [PATCH] [WEB-987] fix: inbox issue activity (#4208) * chore: inbox issue activity * chore: dummy data script * chore: inbox issue activity implementation --------- Co-authored-by: Anmol Singh Bhatia --- apiserver/plane/api/views/inbox.py | 18 ++++++++ apiserver/plane/app/views/inbox/base.py | 19 ++++++++- apiserver/plane/bgtasks/dummy_data_task.py | 5 ++- .../plane/bgtasks/issue_activites_task.py | 41 ++++++++++++++++++ .../issue-activity/activity/actions/inbox.tsx | 42 +++++++++++++++++++ .../issue-activity/activity/actions/index.ts | 1 + .../issue-activity/activity/activity-list.tsx | 3 ++ 7 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 web/components/issues/issue-detail/issue-activity/activity/actions/inbox.tsx diff --git a/apiserver/plane/api/views/inbox.py b/apiserver/plane/api/views/inbox.py index 209b7b658..5e6e4a215 100644 --- a/apiserver/plane/api/views/inbox.py +++ b/apiserver/plane/api/views/inbox.py @@ -272,6 +272,9 @@ class InboxIssueAPIEndpoint(BaseAPIView): serializer = InboxIssueSerializer( inbox_issue, data=request.data, partial=True ) + current_instance = json.dumps( + InboxIssueSerializer(inbox_issue).data, cls=DjangoJSONEncoder + ) if serializer.is_valid(): serializer.save() @@ -311,6 +314,21 @@ class InboxIssueAPIEndpoint(BaseAPIView): issue.state = state issue.save() + # create a activity for status change + issue_activity.delay( + type="inbox.activity.created", + requested_data=json.dumps( + request.data, cls=DjangoJSONEncoder + ), + actor_id=str(request.user.id), + issue_id=str(issue_id), + project_id=str(project_id), + current_instance=current_instance, + epoch=int(timezone.now().timestamp()), + notification=False, + origin=request.META.get("HTTP_ORIGIN"), + ) + return Response(serializer.data, status=status.HTTP_200_OK) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST diff --git a/apiserver/plane/app/views/inbox/base.py b/apiserver/plane/app/views/inbox/base.py index e08434a6d..8e433a127 100644 --- a/apiserver/plane/app/views/inbox/base.py +++ b/apiserver/plane/app/views/inbox/base.py @@ -391,7 +391,9 @@ class InboxIssueViewSet(BaseViewSet): serializer = InboxIssueSerializer( inbox_issue, data=request.data, partial=True ) - + current_instance = json.dumps( + InboxIssueSerializer(inbox_issue).data, cls=DjangoJSONEncoder + ) if serializer.is_valid(): serializer.save() # Update the issue state if the issue is rejected or marked as duplicate @@ -429,6 +431,21 @@ class InboxIssueViewSet(BaseViewSet): if state is not None: issue.state = state issue.save() + # create a activity for status change + issue_activity.delay( + type="inbox.activity.created", + requested_data=json.dumps( + request.data, cls=DjangoJSONEncoder + ), + actor_id=str(request.user.id), + issue_id=str(issue_id), + project_id=str(project_id), + current_instance=current_instance, + epoch=int(timezone.now().timestamp()), + notification=False, + origin=request.META.get("HTTP_ORIGIN"), + ) + inbox_issue = ( InboxIssue.objects.filter( inbox_id=inbox_id.id, diff --git a/apiserver/plane/bgtasks/dummy_data_task.py b/apiserver/plane/bgtasks/dummy_data_task.py index 7ff110e6f..e76cdac22 100644 --- a/apiserver/plane/bgtasks/dummy_data_task.py +++ b/apiserver/plane/bgtasks/dummy_data_task.py @@ -1,4 +1,5 @@ # Python imports +import uuid import random from datetime import datetime, timedelta @@ -36,9 +37,11 @@ from plane.db.models import ( def create_project(workspace, user_id): fake = Faker() name = fake.name() + unique_id = str(uuid.uuid4())[:5] + project = Project.objects.create( workspace=workspace, - name=name, + name=f"{name}_{unique_id}", identifier=name[ : random.randint(2, 12 if len(name) - 1 >= 12 else len(name) - 1) ].upper(), diff --git a/apiserver/plane/bgtasks/issue_activites_task.py b/apiserver/plane/bgtasks/issue_activites_task.py index 9a4e57a49..2d55d5579 100644 --- a/apiserver/plane/bgtasks/issue_activites_task.py +++ b/apiserver/plane/bgtasks/issue_activites_task.py @@ -1553,6 +1553,46 @@ def delete_draft_issue_activity( ) +def create_inbox_activity( + requested_data, + current_instance, + issue_id, + project_id, + workspace_id, + actor_id, + issue_activities, + epoch, +): + requested_data = ( + json.loads(requested_data) if requested_data is not None else None + ) + current_instance = ( + json.loads(current_instance) if current_instance is not None else None + ) + status_dict = { + -2: "Pending", + -1: "Rejected", + 0: "Snoozed", + 1: "Accepted", + 2: "Duplicate", + } + if requested_data.get("status") is not None: + issue_activities.append( + IssueActivity( + issue_id=issue_id, + project_id=project_id, + workspace_id=workspace_id, + comment="updated the inbox status", + field="inbox", + verb=requested_data.get("status"), + actor_id=actor_id, + epoch=epoch, + old_value=status_dict.get(current_instance.get("status")), + new_value=status_dict.get(requested_data.get("status")), + ) + ) + + # Receive message from room group @shared_task def issue_activity( @@ -1613,6 +1653,7 @@ def issue_activity( "issue_draft.activity.created": create_draft_issue_activity, "issue_draft.activity.updated": update_draft_issue_activity, "issue_draft.activity.deleted": delete_draft_issue_activity, + "inbox.activity.created": create_inbox_activity, } func = ACTIVITY_MAPPER.get(type) diff --git a/web/components/issues/issue-detail/issue-activity/activity/actions/inbox.tsx b/web/components/issues/issue-detail/issue-activity/activity/actions/inbox.tsx new file mode 100644 index 000000000..c51c647a9 --- /dev/null +++ b/web/components/issues/issue-detail/issue-activity/activity/actions/inbox.tsx @@ -0,0 +1,42 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +// hooks +import { Inbox } from "lucide-react"; +import { useIssueDetail } from "@/hooks/store"; +// components +import { IssueActivityBlockComponent } from "./"; +// icons + +type TIssueInboxActivity = { activityId: string; ends: "top" | "bottom" | undefined }; + +export const IssueInboxActivity: FC = observer((props) => { + const { activityId, ends } = props; + // hooks + const { + activity: { getActivityById }, + } = useIssueDetail(); + + const activity = getActivityById(activityId); + + const getInboxActivityMessage = () => { + switch (activity?.verb) { + case "-1": + return "declined this issue from inbox."; + case "0": + return "snoozed this issue."; + case "1": + return "accepted this issue from inbox."; + case "2": + return "declined this issue from inbox by marking a duplicate issue."; + default: + return "updated inbox issue status."; + } + }; + + if (!activity) return <>; + return ( + } activityId={activityId} ends={ends}> + <>{getInboxActivityMessage()} + + ); +}); diff --git a/web/components/issues/issue-detail/issue-activity/activity/actions/index.ts b/web/components/issues/issue-detail/issue-activity/activity/actions/index.ts index 02108d70b..7b326aaf9 100644 --- a/web/components/issues/issue-detail/issue-activity/activity/actions/index.ts +++ b/web/components/issues/issue-detail/issue-activity/activity/actions/index.ts @@ -15,6 +15,7 @@ export * from "./label"; export * from "./link"; export * from "./attachment"; export * from "./archived-at"; +export * from "./inbox"; // helpers export * from "./helpers/activity-block"; diff --git a/web/components/issues/issue-detail/issue-activity/activity/activity-list.tsx b/web/components/issues/issue-detail/issue-activity/activity/activity-list.tsx index 42d23eba5..9cdf7999b 100644 --- a/web/components/issues/issue-detail/issue-activity/activity/activity-list.tsx +++ b/web/components/issues/issue-detail/issue-activity/activity/activity-list.tsx @@ -21,6 +21,7 @@ import { IssueLinkActivity, IssueAttachmentActivity, IssueArchivedAtActivity, + IssueInboxActivity, } from "./actions"; type TIssueActivityList = { @@ -74,6 +75,8 @@ export const IssueActivityList: FC = observer((props) => { return ; case "archived_at": return ; + case "inbox": + return ; default: return <>; }