From e73a4bef4ecee846685187cc3b3862dd34c3ff94 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:03:19 +0530 Subject: [PATCH 01/10] chore: issue and project details in activity (#1747) * chore: issue and project details in activity * dev: update capture log --- apiserver/plane/api/serializers/issue.py | 3 ++- apiserver/plane/api/views/issue.py | 2 +- apiserver/plane/api/views/people.py | 2 +- apiserver/plane/api/views/project.py | 2 +- apiserver/plane/api/views/workspace.py | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index ecbb1ca46b7..770880ef035 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -291,7 +291,8 @@ def update(self, instance, validated_data): class IssueActivitySerializer(BaseSerializer): actor_detail = UserLiteSerializer(read_only=True, source="actor") - workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") + issue_detail = IssueFlatSerializer(read_only=True, source="issue") + project_detail = ProjectLiteSerializer(read_only=True, source="project") class Meta: model = IssueActivity diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 38d90ecf9fa..9369ccf2b35 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -477,7 +477,7 @@ def get(self, request, slug, project_id, issue_id): ~Q(field="comment"), project__project_projectmember__member=self.request.user, ) - .select_related("actor", "workspace") + .select_related("actor", "workspace", "issue", "project") ).order_by("created_at") issue_comments = ( IssueComment.objects.filter(issue_id=issue_id) diff --git a/apiserver/plane/api/views/people.py b/apiserver/plane/api/views/people.py index 705f5c96e00..84ee47e4258 100644 --- a/apiserver/plane/api/views/people.py +++ b/apiserver/plane/api/views/people.py @@ -140,7 +140,7 @@ class UserActivityEndpoint(BaseAPIView, BasePaginator): def get(self, request): try: queryset = IssueActivity.objects.filter(actor=request.user).select_related( - "actor", "workspace" + "actor", "workspace", "issue", "project" ) return self.paginate( diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index dfeab07cc0a..0589f4a6180 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -267,7 +267,7 @@ def create(self, request, slug): status=status.HTTP_410_GONE, ) except Exception as e: - pr(e) + capture_exception(e) return Response( {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index 51db47c3dde..b195cedb1ef 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -1190,7 +1190,7 @@ def get(self, request, slug, user_id): workspace__slug=slug, project__project_projectmember__member=request.user, actor=user_id, - ).select_related("actor", "workspace") + ).select_related("actor", "workspace", "issue", "project") if projects: queryset = queryset.filter(project__in=projects) From d315a24c1cf07a8ee3bc4304735f7c3707b04b7b Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:04:23 +0530 Subject: [PATCH 02/10] style: primary color variable added in global (#1748) --- apps/app/styles/globals.css | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/app/styles/globals.css b/apps/app/styles/globals.css index 36d87edf2b3..b8f662902ee 100644 --- a/apps/app/styles/globals.css +++ b/apps/app/styles/globals.css @@ -25,6 +25,25 @@ :root { color-scheme: light !important; + --color-primary-10: 236, 241, 255; + --color-primary-20: 217, 228, 255; + --color-primary-30: 197, 214, 255; + --color-primary-40: 178, 200, 255; + --color-primary-50: 159, 187, 255; + --color-primary-60: 140, 173, 255; + --color-primary-70: 121, 159, 255; + --color-primary-80: 101, 145, 255; + --color-primary-90: 82, 132, 255; + --color-primary-100: 63, 118, 255; + --color-primary-200: 57, 106, 230; + --color-primary-300: 50, 94, 204; + --color-primary-400: 44, 83, 179; + --color-primary-500: 38, 71, 153; + --color-primary-600: 32, 59, 128; + --color-primary-700: 25, 47, 102; + --color-primary-800: 19, 35, 76; + --color-primary-900: 13, 24, 51; + --color-background-100: 255, 255, 255; /* primary bg */ --color-background-90: 250, 250, 250; /* secondary bg */ --color-background-80: 245, 245, 245; /* tertiary bg */ From a8816ef473c38a7cfd22696f3268ef64eebcef3d Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:07:11 +0530 Subject: [PATCH 03/10] refactor: issue activity component (#1749) --- .../core/activity.tsx} | 239 ++++++++++++++++-- apps/app/components/core/index.ts | 1 + apps/app/components/issues/activity.tsx | 15 +- .../issues/comment/comment-card.tsx | 6 +- .../issues/comment/comment-reaction.tsx | 8 +- .../components/profile/overview/activity.tsx | 8 +- apps/app/types/issues.d.ts | 25 +- apps/app/types/users.d.ts | 26 +- 8 files changed, 243 insertions(+), 85 deletions(-) rename apps/app/{helpers/activity.helper.tsx => components/core/activity.tsx} (62%) diff --git a/apps/app/helpers/activity.helper.tsx b/apps/app/components/core/activity.tsx similarity index 62% rename from apps/app/helpers/activity.helper.tsx rename to apps/app/components/core/activity.tsx index af5d9bf1267..078941b02a5 100644 --- a/apps/app/helpers/activity.helper.tsx +++ b/apps/app/components/core/activity.tsx @@ -1,5 +1,7 @@ +import { useRouter } from "next/router"; + // icons -import { Icon } from "components/ui"; +import { Icon, Tooltip } from "components/ui"; import { Squares2X2Icon } from "@heroicons/react/24/outline"; import { BlockedIcon, BlockerIcon } from "components/icons"; // helpers @@ -8,26 +10,65 @@ import { capitalizeFirstLetter } from "helpers/string.helper"; // types import { IIssueActivity } from "types"; -export const activityDetails: { +const IssueLink = ({ activity }: { activity: IIssueActivity }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + return ( + + + {activity.issue_detail + ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` + : "Issue"} + + + + ); +}; + +const activityDetails: { [key: string]: { - message: (activity: IIssueActivity) => React.ReactNode; + message: (activity: IIssueActivity, showIssue: boolean) => React.ReactNode; icon: React.ReactNode; }; } = { assignees: { - message: (activity) => { + message: (activity, showIssue) => { if (activity.old_value === "") return ( <> added a new assignee{" "} - {activity.new_value}. + {activity.new_value} + {showIssue && ( + <> + {" "} + to + > + )} + . > ); else return ( <> removed the assignee{" "} - {activity.old_value}. + {activity.old_value} + {showIssue && ( + <> + {" "} + from + > + )} + . > ); }, @@ -41,7 +82,7 @@ export const activityDetails: { icon: , }, attachment: { - message: (activity) => { + message: (activity, showIssue) => { if (activity.verb === "created") return ( <> @@ -55,9 +96,27 @@ export const activityDetails: { attachment + {showIssue && ( + <> + {" "} + to + > + )} + > + ); + else + return ( + <> + removed an attachment + {showIssue && ( + <> + {" "} + from + > + )} + . > ); - else return "removed an attachment."; }, icon: , }, @@ -126,17 +185,47 @@ export const activityDetails: { icon: , }, description: { - message: (activity) => "updated the description.", + message: (activity, showIssue) => ( + <> + updated the description + {showIssue && ( + <> + {" "} + of + > + )} + . + > + ), icon: , }, estimate_point: { - message: (activity) => { - if (!activity.new_value) return "removed the estimate point."; + message: (activity, showIssue) => { + if (!activity.new_value) + return ( + <> + removed the estimate point + {showIssue && ( + <> + {" "} + from + > + )} + . + > + ); else return ( <> set the estimate point to{" "} - {activity.new_value}. + {activity.new_value} + {showIssue && ( + <> + {" "} + for + > + )} + . > ); }, @@ -150,7 +239,7 @@ export const activityDetails: { icon: , }, labels: { - message: (activity) => { + message: (activity, showIssue) => { if (activity.old_value === "") return ( <> @@ -165,6 +254,12 @@ export const activityDetails: { /> {activity.new_value} + {showIssue && ( + <> + {" "} + to + > + )} > ); else @@ -181,13 +276,19 @@ export const activityDetails: { /> {activity.old_value} + {showIssue && ( + <> + {" "} + from + > + )} > ); }, icon: , }, link: { - message: (activity) => { + message: (activity, showIssue) => { if (activity.verb === "created") return ( <> @@ -200,8 +301,14 @@ export const activityDetails: { > link - {" "} - to the issue. + + {showIssue && ( + <> + {" "} + to + > + )} + . > ); else @@ -216,8 +323,14 @@ export const activityDetails: { > link - {" "} - from the issue. + + {showIssue && ( + <> + {" "} + from + > + )} + . > ); }, @@ -250,52 +363,102 @@ export const activityDetails: { icon: , }, name: { - message: (activity) => `set the name to ${activity.new_value}.`, + message: (activity, showIssue) => ( + <> + set the name to {activity.new_value} + {showIssue && ( + <> + {" "} + of + > + )} + . + > + ), icon: , }, parent: { - message: (activity) => { + message: (activity, showIssue) => { if (!activity.new_value) return ( <> removed the parent{" "} - {activity.old_value}. + {activity.old_value} + {showIssue && ( + <> + {" "} + from + > + )} + . > ); else return ( <> set the parent to{" "} - {activity.new_value}. + {activity.new_value} + {showIssue && ( + <> + {" "} + for + > + )} + . > ); }, icon: , }, priority: { - message: (activity) => ( + message: (activity, showIssue) => ( <> set the priority to{" "} {activity.new_value ? capitalizeFirstLetter(activity.new_value) : "None"} + {showIssue && ( + <> + {" "} + for + > + )} . > ), icon: , }, state: { - message: (activity) => ( + message: (activity, showIssue) => ( <> set the state to{" "} - {activity.new_value}. + {activity.new_value} + {showIssue && ( + <> + {" "} + for + > + )} + . > ), icon: , }, target_date: { - message: (activity) => { - if (!activity.new_value) return "removed the due date."; + message: (activity, showIssue) => { + if (!activity.new_value) + return ( + <> + removed the due date + {showIssue && ( + <> + {" "} + from + > + )} + . + > + ); else return ( <> @@ -303,6 +466,12 @@ export const activityDetails: { {renderShortDateWithYearFormat(activity.new_value)} + {showIssue && ( + <> + {" "} + for + > + )} . > ); @@ -310,3 +479,19 @@ export const activityDetails: { icon: , }, }; + +export const ActivityIcon = ({ activity }: { activity: IIssueActivity }) => ( + <>{activityDetails[activity.field as keyof typeof activityDetails].icon}> +); + +export const ActivityMessage = ({ + activity, + showIssue = false, +}: { + activity: IIssueActivity; + showIssue?: boolean; +}) => ( + <> + {activityDetails[activity.field as keyof typeof activityDetails].message(activity, showIssue)} + > +); diff --git a/apps/app/components/core/index.ts b/apps/app/components/core/index.ts index 4baefbd5bf2..259655ae78d 100644 --- a/apps/app/components/core/index.ts +++ b/apps/app/components/core/index.ts @@ -3,6 +3,7 @@ export * from "./modals"; export * from "./sidebar"; export * from "./theme"; export * from "./views"; +export * from "./activity"; export * from "./feeds"; export * from "./reaction-selector"; export * from "./image-picker-popover"; diff --git a/apps/app/components/issues/activity.tsx b/apps/app/components/issues/activity.tsx index 540d81df91c..54dc3961398 100644 --- a/apps/app/components/issues/activity.tsx +++ b/apps/app/components/issues/activity.tsx @@ -8,12 +8,12 @@ import useSWR from "swr"; // services import issuesService from "services/issues.service"; // components +import { ActivityIcon, ActivityMessage } from "components/core"; import { CommentCard } from "components/issues/comment"; // ui import { Icon, Loader } from "components/ui"; // helpers import { timeAgo } from "helpers/date-time.helper"; -import { activityDetails } from "helpers/activity.helper"; // types import { ICurrentUserResponse, IIssueComment } from "types"; // fetch-keys @@ -91,11 +91,11 @@ export const IssueActivitySection: React.FC = ({ issueId, user }) => { {issueActivities.map((activityItem, index) => { // determines what type of action is performed - const message = activityItem.field - ? activityDetails[activityItem.field as keyof typeof activityDetails]?.message( - activityItem - ) - : "created the issue."; + const message = activityItem.field ? ( + + ) : ( + "created the issue." + ); if ("field" in activityItem && activityItem.field !== "updated_by") { return ( @@ -116,8 +116,7 @@ export const IssueActivitySection: React.FC = ({ issueId, user }) => { activityItem.new_value === "restore" ? ( ) : ( - activityDetails[activityItem.field as keyof typeof activityDetails] - ?.icon + ) ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? ( diff --git a/apps/app/components/issues/comment/comment-card.tsx b/apps/app/components/issues/comment/comment-card.tsx index a78be0fa1a2..987254f3b57 100644 --- a/apps/app/components/issues/comment/comment-card.tsx +++ b/apps/app/components/issues/comment/comment-card.tsx @@ -140,11 +140,7 @@ export const CommentCard: React.FC = ({ comment, onSubmit, handleCommentD ref={showEditorRef} /> - + diff --git a/apps/app/components/issues/comment/comment-reaction.tsx b/apps/app/components/issues/comment/comment-reaction.tsx index 33e12bc6fd0..b6ce3bbbcae 100644 --- a/apps/app/components/issues/comment/comment-reaction.tsx +++ b/apps/app/components/issues/comment/comment-reaction.tsx @@ -1,5 +1,7 @@ import React from "react"; +import { useRouter } from "next/router"; + // hooks import useUser from "hooks/use-user"; import useCommentReaction from "hooks/use-comment-reaction"; @@ -9,13 +11,15 @@ import { ReactionSelector } from "components/core"; import { renderEmoji } from "helpers/emoji.helper"; type Props = { - workspaceSlug?: string | string[]; projectId?: string | string[]; commentId: string; }; export const CommentReaction: React.FC = (props) => { - const { workspaceSlug, projectId, commentId } = props; + const { projectId, commentId } = props; + + const router = useRouter(); + const { workspaceSlug } = router.query; const { user } = useUser(); diff --git a/apps/app/components/profile/overview/activity.tsx b/apps/app/components/profile/overview/activity.tsx index 28801ed8fec..eb34780208a 100644 --- a/apps/app/components/profile/overview/activity.tsx +++ b/apps/app/components/profile/overview/activity.tsx @@ -1,14 +1,14 @@ import { useRouter } from "next/router"; -import Link from "next/link"; import useSWR from "swr"; // services import userService from "services/user.service"; +// components +import { ActivityMessage } from "components/core"; // ui import { Icon, Loader } from "components/ui"; // helpers -import { activityDetails } from "helpers/activity.helper"; import { timeAgo } from "helpers/date-time.helper"; // fetch-keys import { USER_PROFILE_ACTIVITY } from "constants/fetch-keys"; @@ -55,12 +55,12 @@ export const ProfileActivity = () => { {activity.actor_detail.first_name} {activity.actor_detail.last_name}{" "} {activity.field ? ( - activityDetails[activity.field]?.message(activity as any) + ) : ( created this{" "} Date: Tue, 1 Aug 2023 18:25:13 +0530 Subject: [PATCH 04/10] style: profile dropdown updated (#1751) --- apps/app/components/workspace/sidebar-dropdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/components/workspace/sidebar-dropdown.tsx b/apps/app/components/workspace/sidebar-dropdown.tsx index c9addf8db49..3b9aa97eb9a 100644 --- a/apps/app/components/workspace/sidebar-dropdown.tsx +++ b/apps/app/components/workspace/sidebar-dropdown.tsx @@ -284,7 +284,7 @@ export const WorkspaceSidebarDropdown = () => { onClick={handleSignOut} > - Log out + Sign out From d22e4b8212d26d34e1c2a6b82ce4f304518b31eb Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Tue, 1 Aug 2023 18:38:33 +0530 Subject: [PATCH 05/10] fix: profile activity workspace slug (#1752) --- apps/app/components/core/feeds.tsx | 441 +++++++++++++++-------------- 1 file changed, 226 insertions(+), 215 deletions(-) diff --git a/apps/app/components/core/feeds.tsx b/apps/app/components/core/feeds.tsx index 6b6576b3658..2924ec45685 100644 --- a/apps/app/components/core/feeds.tsx +++ b/apps/app/components/core/feeds.tsx @@ -1,5 +1,7 @@ import React from "react"; +import { useRouter } from "next/router"; + import Link from "next/link"; // icons @@ -99,233 +101,242 @@ const activityDetails: { }, }; -export const Feeds: React.FC = ({ activities }) => ( - - - {activities.map((activity: any, activityIdx: number) => { - // determines what type of action is performed - let action = activityDetails[activity.field as keyof typeof activityDetails]?.message; - if (activity.field === "labels") { - action = activity.new_value !== "" ? "added a new label" : "removed the label"; - } else if (activity.field === "blocking") { - action = - activity.new_value !== "" - ? "marked this issue is blocking" - : "removed the issue from blocking"; - } else if (activity.field === "blocks") { - action = - activity.new_value !== "" ? "marked this issue being blocked by" : "removed blocker"; - } else if (activity.field === "target_date") { - action = - activity.new_value && activity.new_value !== "" - ? "set the due date to" - : "removed the due date"; - } else if (activity.field === "parent") { - action = - activity.new_value && activity.new_value !== "" - ? "set the parent to" - : "removed the parent"; - } else if (activity.field === "priority") { - action = - activity.new_value && activity.new_value !== "" - ? "set the priority to" - : "removed the priority"; - } else if (activity.field === "description") { - action = "updated the"; - } else if (activity.field === "attachment") { - action = `${activity.verb} the`; - } else if (activity.field === "link") { - action = `${activity.verb} the`; - } else if (activity.field === "archived_at") { - action = - activity.new_value && activity.new_value === "restore" - ? "restored the issue" - : "archived the issue"; - } - // for values that are after the action clause - let value: any = activity.new_value ? activity.new_value : activity.old_value; - if ( - activity.verb === "created" && - activity.field !== "cycles" && - activity.field !== "modules" && - activity.field !== "attachment" && - activity.field !== "link" && - activity.field !== "estimate" - ) { - const { workspace_detail, project, issue } = activity; - value = ( - - created{" "} - - - this issue. - - - - ); - } else if (activity.field === "state") { - value = activity.new_value ? addSpaceIfCamelCase(activity.new_value) : "None"; - } else if (activity.field === "labels") { - let name; - let id = "#000000"; - if (activity.new_value !== "") { - name = activity.new_value; - id = activity.new_identifier ? activity.new_identifier : id; - } else { - name = activity.old_value; - id = activity.old_identifier ? activity.old_identifier : id; +export const Feeds: React.FC = ({ activities }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + return ( + + + {activities.map((activity: any, activityIdx: number) => { + // determines what type of action is performed + let action = activityDetails[activity.field as keyof typeof activityDetails]?.message; + if (activity.field === "labels") { + action = activity.new_value !== "" ? "added a new label" : "removed the label"; + } else if (activity.field === "blocking") { + action = + activity.new_value !== "" + ? "marked this issue is blocking" + : "removed the issue from blocking"; + } else if (activity.field === "blocks") { + action = + activity.new_value !== "" ? "marked this issue being blocked by" : "removed blocker"; + } else if (activity.field === "target_date") { + action = + activity.new_value && activity.new_value !== "" + ? "set the due date to" + : "removed the due date"; + } else if (activity.field === "parent") { + action = + activity.new_value && activity.new_value !== "" + ? "set the parent to" + : "removed the parent"; + } else if (activity.field === "priority") { + action = + activity.new_value && activity.new_value !== "" + ? "set the priority to" + : "removed the priority"; + } else if (activity.field === "description") { + action = "updated the"; + } else if (activity.field === "attachment") { + action = `${activity.verb} the`; + } else if (activity.field === "link") { + action = `${activity.verb} the`; + } else if (activity.field === "archived_at") { + action = + activity.new_value && activity.new_value === "restore" + ? "restored the issue" + : "archived the issue"; } + // for values that are after the action clause + let value: any = activity.new_value ? activity.new_value : activity.old_value; + if ( + activity.verb === "created" && + activity.field !== "cycles" && + activity.field !== "modules" && + activity.field !== "attachment" && + activity.field !== "link" && + activity.field !== "estimate" + ) { + const { project, issue } = activity; + value = ( + + created{" "} + + + this issue. + + + + ); + } else if (activity.field === "state") { + value = activity.new_value ? addSpaceIfCamelCase(activity.new_value) : "None"; + } else if (activity.field === "labels") { + let name; + let id = "#000000"; + if (activity.new_value !== "") { + name = activity.new_value; + id = activity.new_identifier ? activity.new_identifier : id; + } else { + name = activity.old_value; + id = activity.old_identifier ? activity.old_identifier : id; + } - value = name; - } else if (activity.field === "assignees") { - value = activity.new_value; - } else if (activity.field === "target_date") { - const date = - activity.new_value && activity.new_value !== "" - ? activity.new_value - : activity.old_value; - value = renderShortDateWithYearFormat(date as string); - } else if (activity.field === "description") { - value = "description"; - } else if (activity.field === "attachment") { - value = "attachment"; - } else if (activity.field === "link") { - value = "link"; - } else if (activity.field === "estimate_point") { - value = activity.new_value - ? activity.new_value + ` Point${parseInt(activity.new_value ?? "", 10) > 1 ? "s" : ""}` - : "None"; - } + value = name; + } else if (activity.field === "assignees") { + value = activity.new_value; + } else if (activity.field === "target_date") { + const date = + activity.new_value && activity.new_value !== "" + ? activity.new_value + : activity.old_value; + value = renderShortDateWithYearFormat(date as string); + } else if (activity.field === "description") { + value = "description"; + } else if (activity.field === "attachment") { + value = "attachment"; + } else if (activity.field === "link") { + value = "link"; + } else if (activity.field === "estimate_point") { + value = activity.new_value + ? activity.new_value + + ` Point${parseInt(activity.new_value ?? "", 10) > 1 ? "s" : ""}` + : "None"; + } - if (activity.field === "comment") { - return ( - - - - {activity.field ? ( - activity.new_value === "restore" ? ( - + if (activity.field === "comment") { + return ( + + + + {activity.field ? ( + activity.new_value === "restore" ? ( + + ) : ( + activityDetails[activity.field as keyof typeof activityDetails]?.icon + ) + ) : activity.actor_detail.avatar && activity.actor_detail.avatar !== "" ? ( + ) : ( - activityDetails[activity.field as keyof typeof activityDetails]?.icon - ) - ) : activity.actor_detail.avatar && activity.actor_detail.avatar !== "" ? ( - - ) : ( - - {activity.actor_detail.first_name.charAt(0)} - - )} + + {activity.actor_detail.first_name.charAt(0)} + + )} - - - - - - - - {activity.actor_detail.first_name} - {activity.actor_detail.is_bot ? "Bot" : " " + activity.actor_detail.last_name} - - - Commented {timeAgo(activity.created_at)} - + + + - - + + + + {activity.actor_detail.first_name} + {activity.actor_detail.is_bot + ? "Bot" + : " " + activity.actor_detail.last_name} + + + Commented {timeAgo(activity.created_at)} + + + + + - - ); - } + ); + } - if ("field" in activity && activity.field !== "updated_by") { - return ( - - - {activities.length > 1 && activityIdx !== activities.length - 1 ? ( - - ) : null} - - <> - - - - - {activity.field ? ( - activityDetails[activity.field as keyof typeof activityDetails]?.icon - ) : activity.actor_detail.avatar && - activity.actor_detail.avatar !== "" ? ( - - ) : ( - - {activity.actor_detail.first_name.charAt(0)} - - )} + if ("field" in activity && activity.field !== "updated_by") { + return ( + + + {activities.length > 1 && activityIdx !== activities.length - 1 ? ( + + ) : null} + + <> + + + + + {activity.field ? ( + activityDetails[activity.field as keyof typeof activityDetails] + ?.icon + ) : activity.actor_detail.avatar && + activity.actor_detail.avatar !== "" ? ( + + ) : ( + + {activity.actor_detail.first_name.charAt(0)} + + )} + - - - - {activity.field === "archived_at" && activity.new_value !== "restore" ? ( - Plane - ) : ( - - {activity.actor_detail.first_name} - {activity.actor_detail.is_bot - ? " Bot" - : " " + activity.actor_detail.last_name} - - )} - {action} - {activity.field !== "archived_at" && ( - - {" "} - {value}{" "} - - )} - {timeAgo(activity.created_at)} + + + {activity.field === "archived_at" && activity.new_value !== "restore" ? ( + Plane + ) : ( + + {activity.actor_detail.first_name} + {activity.actor_detail.is_bot + ? " Bot" + : " " + activity.actor_detail.last_name} + + )} + {action} + {activity.field !== "archived_at" && ( + + {" "} + {value}{" "} + + )} + {timeAgo(activity.created_at)} + - - > + > + - - - ); - } - })} - - -); + + ); + } + })} + + + ); +}; From 2cd431b4a45f7767834a1bda96319c0fb90c67dd Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Tue, 1 Aug 2023 18:40:04 +0530 Subject: [PATCH 06/10] fix: my issues mutation (#1753) * fix: my issues mutation * fix: activity message and icon return value --- apps/app/components/core/activity.tsx | 4 ++-- apps/app/components/issues/modal.tsx | 4 ++++ .../profile/profile-issues-view.tsx | 19 +++++++++++++++---- apps/app/hooks/my-issues/use-my-issues.tsx | 12 ++++++++++-- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/apps/app/components/core/activity.tsx b/apps/app/components/core/activity.tsx index 078941b02a5..f7622baa6d2 100644 --- a/apps/app/components/core/activity.tsx +++ b/apps/app/components/core/activity.tsx @@ -481,7 +481,7 @@ const activityDetails: { }; export const ActivityIcon = ({ activity }: { activity: IIssueActivity }) => ( - <>{activityDetails[activity.field as keyof typeof activityDetails].icon}> + <>{activityDetails[activity.field as keyof typeof activityDetails]?.icon}> ); export const ActivityMessage = ({ @@ -492,6 +492,6 @@ export const ActivityMessage = ({ showIssue?: boolean; }) => ( <> - {activityDetails[activity.field as keyof typeof activityDetails].message(activity, showIssue)} + {activityDetails[activity.field as keyof typeof activityDetails]?.message(activity, showIssue)} > ); diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index c738dbf07ae..be3b556a122 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -18,6 +18,7 @@ import useToast from "hooks/use-toast"; import useInboxView from "hooks/use-inbox-view"; import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useProjects from "hooks/use-projects"; +import useMyIssues from "hooks/my-issues/use-my-issues"; // components import { IssueForm } from "components/issues"; // types @@ -85,6 +86,8 @@ export const CreateUpdateIssueModal: React.FC = ({ const { user } = useUser(); const { projects } = useProjects(); + const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); + const { setToastAlert } = useToast(); if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; @@ -243,6 +246,7 @@ export const CreateUpdateIssueModal: React.FC = ({ if (issueView === "calendar") mutate(calendarFetchKey); if (issueView === "gantt_chart") mutate(ganttFetchKey); if (issueView === "spreadsheet") mutate(spreadsheetFetchKey); + if (groupedIssues) mutateMyIssues(); setToastAlert({ type: "success", diff --git a/apps/app/components/profile/profile-issues-view.tsx b/apps/app/components/profile/profile-issues-view.tsx index 64632f0b989..401ac22d377 100644 --- a/apps/app/components/profile/profile-issues-view.tsx +++ b/apps/app/components/profile/profile-issues-view.tsx @@ -8,6 +8,7 @@ import useSWR from "swr"; import { DropResult } from "react-beautiful-dnd"; // services import issuesService from "services/issues.service"; +import userService from "services/user.service"; // hooks import useProfileIssues from "hooks/use-profile-issues"; import useUser from "hooks/use-user"; @@ -19,7 +20,7 @@ import { orderArrayBy } from "helpers/array.helper"; // types import { IIssue, IIssueFilterOptions } from "types"; // fetch-keys -import { WORKSPACE_LABELS } from "constants/fetch-keys"; +import { USER_PROFILE_PROJECT_SEGREGATION, WORKSPACE_LABELS } from "constants/fetch-keys"; export const ProfileIssuesView = () => { // create issue modal @@ -60,6 +61,16 @@ export const ProfileIssuesView = () => { params, } = useProfileIssues(workspaceSlug?.toString(), userId?.toString()); + const { data: profileData } = useSWR( + workspaceSlug && userId + ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) + : null, + workspaceSlug && userId + ? () => + userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString()) + : null + ); + const { data: labels } = useSWR( workspaceSlug && (filters?.labels ?? []).length > 0 ? WORKSPACE_LABELS(workspaceSlug.toString()) @@ -268,10 +279,10 @@ export const ProfileIssuesView = () => { dragDisabled={groupByProperty !== "priority"} emptyState={{ title: router.pathname.includes("assigned") - ? `Issues assigned to ${user?.first_name} ${user?.last_name} will appear here` + ? `Issues assigned to ${profileData?.user_data.first_name} ${profileData?.user_data.last_name} will appear here` : router.pathname.includes("created") - ? `Issues created by ${user?.first_name} ${user?.last_name} will appear here` - : `Issues subscribed by ${user?.first_name} ${user?.last_name} will appear here`, + ? `Issues created by ${profileData?.user_data.first_name} ${profileData?.user_data.last_name} will appear here` + : `Issues subscribed by ${profileData?.user_data.first_name} ${profileData?.user_data.last_name} will appear here`, }} handleOnDragEnd={handleOnDragEnd} handleIssueAction={handleIssueAction} diff --git a/apps/app/hooks/my-issues/use-my-issues.tsx b/apps/app/hooks/my-issues/use-my-issues.tsx index 164fad4d431..f9063b4de0c 100644 --- a/apps/app/hooks/my-issues/use-my-issues.tsx +++ b/apps/app/hooks/my-issues/use-my-issues.tsx @@ -1,5 +1,7 @@ import { useMemo } from "react"; +import { useRouter } from "next/router"; + import useSWR from "swr"; // services @@ -12,6 +14,8 @@ import { IIssue } from "types"; import { USER_ISSUES } from "constants/fetch-keys"; const useMyIssues = (workspaceSlug: string | undefined) => { + const router = useRouter(); + const { filters, groupBy, orderBy } = useMyIssuesFilters(workspaceSlug); const params: any = { @@ -27,8 +31,12 @@ const useMyIssues = (workspaceSlug: string | undefined) => { }; const { data: myIssues, mutate: mutateMyIssues } = useSWR( - workspaceSlug ? USER_ISSUES(workspaceSlug.toString(), params) : null, - workspaceSlug ? () => userService.userIssues(workspaceSlug.toString(), params) : null + workspaceSlug && router.pathname.includes("my-issues") + ? USER_ISSUES(workspaceSlug.toString(), params) + : null, + workspaceSlug && router.pathname.includes("my-issues") + ? () => userService.userIssues(workspaceSlug.toString(), params) + : null ); const groupedIssues: From d83a76a3aa2b00aeff5d622f2c1dfda4fd402915 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 1 Aug 2023 19:04:53 +0530 Subject: [PATCH 07/10] style: my issue and profile page view dropdown (#1754) --- .../my-issues/my-issues-view-options.tsx | 155 ++++++++--------- .../profile/profile-issues-view-options.tsx | 157 +++++++++--------- 2 files changed, 159 insertions(+), 153 deletions(-) diff --git a/apps/app/components/issues/my-issues/my-issues-view-options.tsx b/apps/app/components/issues/my-issues/my-issues-view-options.tsx index 24d59fa0391..35ed2295ccc 100644 --- a/apps/app/components/issues/my-issues/my-issues-view-options.tsx +++ b/apps/app/components/issues/my-issues/my-issues-view-options.tsx @@ -146,105 +146,108 @@ export const MyIssuesViewOptions: React.FC = () => { <> Group by - option.key === groupBy)?.name ?? - "Select" - } - > - {GROUP_BY_OPTIONS.map((option) => { - if (issueView === "kanban" && option.key === null) return null; - if (option.key === "state" || option.key === "created_by") - return null; + + option.key === groupBy) + ?.name ?? "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {GROUP_BY_OPTIONS.map((option) => { + if (issueView === "kanban" && option.key === null) return null; + if (option.key === "state" || option.key === "created_by") + return null; - return ( - setGroupBy(option.key)} - > - {option.name} - - ); - })} - + return ( + setGroupBy(option.key)} + > + {option.name} + + ); + })} + + Order by - option.key === orderBy)?.name ?? - "Select" - } - > - {ORDER_BY_OPTIONS.map((option) => { - if (groupBy === "priority" && option.key === "priority") return null; - if (option.key === "sort_order") return null; + + option.key === orderBy)?.name ?? + "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {ORDER_BY_OPTIONS.map((option) => { + if (groupBy === "priority" && option.key === "priority") + return null; + if (option.key === "sort_order") return null; - return ( - { - setOrderBy(option.key); - }} - > - {option.name} - - ); - })} - + return ( + { + setOrderBy(option.key); + }} + > + {option.name} + + ); + })} + + > )} Issue type - option.key === filters?.type) - ?.name ?? "Select" - } - > - {FILTER_ISSUE_OPTIONS.map((option) => ( - - setFilters({ - type: option.key, - }) - } - > - {option.name} - - ))} - + + option.key === filters?.type) + ?.name ?? "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {FILTER_ISSUE_OPTIONS.map((option) => ( + + setFilters({ + type: option.key, + }) + } + > + {option.name} + + ))} + + {issueView !== "calendar" && issueView !== "spreadsheet" && ( <> Show empty states - + + + - {/* - resetFilterToDefault()}> - Reset to default - - setNewFilterDefaultView()} - > - Set as default - - */} > )} Display Properties - + {Object.keys(properties).map((key) => { if (key === "estimate" && !isEstimateActive) return null; diff --git a/apps/app/components/profile/profile-issues-view-options.tsx b/apps/app/components/profile/profile-issues-view-options.tsx index 0441987eb30..94ba6ef176f 100644 --- a/apps/app/components/profile/profile-issues-view-options.tsx +++ b/apps/app/components/profile/profile-issues-view-options.tsx @@ -172,106 +172,109 @@ export const ProfileIssuesViewOptions: React.FC = () => { <> Group by - option.key === groupByProperty) - ?.name ?? "Select" - } - > - {GROUP_BY_OPTIONS.map((option) => { - if (issueView === "kanban" && option.key === null) return null; - if (option.key === "state" || option.key === "created_by") - return null; + + option.key === groupByProperty + )?.name ?? "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {GROUP_BY_OPTIONS.map((option) => { + if (issueView === "kanban" && option.key === null) return null; + if (option.key === "state" || option.key === "created_by") + return null; - return ( - setGroupByProperty(option.key)} - > - {option.name} - - ); - })} - + return ( + setGroupByProperty(option.key)} + > + {option.name} + + ); + })} + + Order by - option.key === orderBy)?.name ?? - "Select" - } - > - {ORDER_BY_OPTIONS.map((option) => { - if (groupByProperty === "priority" && option.key === "priority") - return null; - if (option.key === "sort_order") return null; + + option.key === orderBy)?.name ?? + "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {ORDER_BY_OPTIONS.map((option) => { + if (groupByProperty === "priority" && option.key === "priority") + return null; + if (option.key === "sort_order") return null; - return ( - { - setOrderBy(option.key); - }} - > - {option.name} - - ); - })} - + return ( + { + setOrderBy(option.key); + }} + > + {option.name} + + ); + })} + + > )} Issue type - option.key === filters?.type) - ?.name ?? "Select" - } - > - {FILTER_ISSUE_OPTIONS.map((option) => ( - - setFilters({ - type: option.key, - }) - } - > - {option.name} - - ))} - + + option.key === filters?.type) + ?.name ?? "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {FILTER_ISSUE_OPTIONS.map((option) => ( + + setFilters({ + type: option.key, + }) + } + > + {option.name} + + ))} + + {issueView !== "calendar" && issueView !== "spreadsheet" && ( <> Show empty states - + + + - {/* - resetFilterToDefault()}> - Reset to default - - setNewFilterDefaultView()} - > - Set as default - - */} > )} Display Properties - + {Object.keys(properties).map((key) => { if (key === "estimate" && !isEstimateActive) return null; From f3bd1691ce5d1ff9ef130e3e82542a82f48fac3a Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 1 Aug 2023 19:11:09 +0530 Subject: [PATCH 08/10] style: sidebar project list styling (#1756) --- apps/app/components/project/single-sidebar-project.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/components/project/single-sidebar-project.tsx b/apps/app/components/project/single-sidebar-project.tsx index 64227b7a348..acc1f493e62 100644 --- a/apps/app/components/project/single-sidebar-project.tsx +++ b/apps/app/components/project/single-sidebar-project.tsx @@ -137,7 +137,7 @@ export const SingleSidebarProject: React.FC = ({ {({ open }) => ( <> From 11525f26d00b646d3e45413fc35dfd3a1e0c0d94 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Tue, 1 Aug 2023 19:11:32 +0530 Subject: [PATCH 09/10] fix: project identifier migration (#1755) --- ...40_projectmember_preferences_user_cover_image_and_more.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py b/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py index b7ca6550078..7a321f2c836 100644 --- a/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py +++ b/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py @@ -67,5 +67,10 @@ class Migration(migrations.Migration): 'ordering': ('-created_at',), 'unique_together': {('comment', 'actor', 'reaction')}, }, + ), + migrations.AlterField( + model_name='project', + name='identifier', + field=models.CharField(max_length=12, verbose_name='Project Identifier'), ), ] From 6ea15ced0259d0f6a58510ee4f1f79dac3f82aa8 Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Tue, 1 Aug 2023 19:25:04 +0530 Subject: [PATCH 10/10] fix: project identifier length (#1757) --- ...40_projectmember_preferences_user_cover_image_and_more.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py b/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py index 7a321f2c836..5662ef666af 100644 --- a/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py +++ b/apiserver/plane/db/migrations/0040_projectmember_preferences_user_cover_image_and_more.py @@ -73,4 +73,9 @@ class Migration(migrations.Migration): name='identifier', field=models.CharField(max_length=12, verbose_name='Project Identifier'), ), + migrations.AlterField( + model_name='projectidentifier', + name='name', + field=models.CharField(max_length=12), + ), ]
- Commented {timeAgo(activity.created_at)} -
+ Commented {timeAgo(activity.created_at)} +