From 969a51f425a29026586c19ba0a80415db10191b5 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:11:14 +0530 Subject: [PATCH] chore: issue click & peek overview improvement (#3157) * improve issue popover to detect outside click * chore: stopPropagation event added to prevent peekoverview triggering in action menu & issue properties * chore: stopPropagation event added to prevent peekoverview triggering in issue properties * chore: enable entire issue card clickability in list and kanban layout, introduce control-click functionality to open issues in new tabs * chore: build error fix and unused variable removed * chore: build error fix --------- Co-authored-by: sriram veeraghanta --- .../issue-layouts/calendar/issue-blocks.tsx | 18 +++-- .../issues/issue-layouts/gantt/blocks.tsx | 16 ++-- .../issues/issue-layouts/kanban/block.tsx | 79 +++++++++++-------- .../issues/issue-layouts/list/block.tsx | 28 ++++--- .../issue-layouts/properties/assignee.tsx | 6 +- .../issues/issue-layouts/properties/date.tsx | 5 +- .../issue-layouts/properties/estimates.tsx | 2 + .../issue-layouts/properties/labels.tsx | 6 +- .../issues/issue-layouts/properties/state.tsx | 6 +- .../quick-action-dropdowns/all-issue.tsx | 7 +- .../quick-action-dropdowns/archived-issue.tsx | 7 +- .../quick-action-dropdowns/cycle-issue.tsx | 7 +- .../quick-action-dropdowns/module-issue.tsx | 8 +- .../quick-action-dropdowns/project-issue.tsx | 7 +- .../columns/issue/issue-column.tsx | 18 +++-- .../spreadsheet/columns/state-column.tsx | 2 - web/components/issues/peek-overview/view.tsx | 9 ++- web/components/issues/sub-issues/issue.tsx | 16 ++-- web/components/project/priority-select.tsx | 2 + 19 files changed, 167 insertions(+), 82 deletions(-) diff --git a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx index c2532b802..f8eead33f 100644 --- a/web/components/issues/issue-layouts/calendar/issue-blocks.tsx +++ b/web/components/issues/issue-layouts/calendar/issue-blocks.tsx @@ -36,13 +36,17 @@ export const CalendarIssueBlocks: React.FC = observer((props) => { const menuActionRef = useRef(null); - const handleIssuePeekOverview = (issue: IIssue) => { + const handleIssuePeekOverview = (issue: IIssue, event: React.MouseEvent) => { const { query } = router; - - router.push({ - pathname: router.pathname, - query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, - }); + if (event.ctrlKey || event.metaKey) { + const issueUrl = `/${issue.workspace_detail.slug}/projects/${issue.project_detail.id}/issues/${issue?.id}`; + window.open(issueUrl, "_blank"); // Open link in a new tab + } else { + router.push({ + pathname: router.pathname, + query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, + }); + } }; useOutsideClickDetector(menuActionRef, () => setIsMenuActive(false)); @@ -75,7 +79,7 @@ export const CalendarIssueBlocks: React.FC = observer((props) => { {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} - onClick={() => handleIssuePeekOverview(issue)} + onClick={(e) => handleIssuePeekOverview(issue, e)} > {issue?.tempId !== undefined && (
diff --git a/web/components/issues/issue-layouts/gantt/blocks.tsx b/web/components/issues/issue-layouts/gantt/blocks.tsx index 916dceedf..41085978a 100644 --- a/web/components/issues/issue-layouts/gantt/blocks.tsx +++ b/web/components/issues/issue-layouts/gantt/blocks.tsx @@ -9,13 +9,17 @@ import { IIssue } from "types"; export const IssueGanttBlock = ({ data }: { data: IIssue }) => { const router = useRouter(); - const handleIssuePeekOverview = () => { + const handleIssuePeekOverview = (event: React.MouseEvent) => { const { query } = router; - - router.push({ - pathname: router.pathname, - query: { ...query, peekIssueId: data?.id, peekProjectId: data?.project }, - }); + if (event.ctrlKey || event.metaKey) { + const issueUrl = `/${data?.workspace_detail.slug}/projects/${data?.project_detail.id}/issues/${data?.id}`; + window.open(issueUrl, "_blank"); // Open link in a new tab + } else { + router.push({ + pathname: router.pathname, + query: { ...query, peekIssueId: data?.id, peekProjectId: data?.project }, + }); + } }; return ( diff --git a/web/components/issues/issue-layouts/kanban/block.tsx b/web/components/issues/issue-layouts/kanban/block.tsx index 065b409a6..b48698fa7 100644 --- a/web/components/issues/issue-layouts/kanban/block.tsx +++ b/web/components/issues/issue-layouts/kanban/block.tsx @@ -1,5 +1,5 @@ import { memo } from "react"; -import { Draggable } from "@hello-pangea/dnd"; +import { Draggable, DraggableStateSnapshot } from "@hello-pangea/dnd"; import isEqual from "lodash/isEqual"; // components import { KanBanProperties } from "./properties"; @@ -32,11 +32,23 @@ interface IssueDetailsBlockProps { quickActions: (sub_group_by: string | null, group_by: string | null, issue: IIssue) => React.ReactNode; displayProperties: IIssueDisplayProperties | null; isReadOnly: boolean; + snapshot: DraggableStateSnapshot; + isDragDisabled: boolean; } const KanbanIssueDetailsBlock: React.FC = (props) => { - const { sub_group_id, columnId, issue, showEmptyGroup, handleIssues, quickActions, displayProperties, isReadOnly } = - props; + const { + sub_group_id, + columnId, + issue, + showEmptyGroup, + handleIssues, + quickActions, + displayProperties, + isReadOnly, + snapshot, + isDragDisabled, + } = props; const router = useRouter(); @@ -44,20 +56,29 @@ const KanbanIssueDetailsBlock: React.FC = (props) => { if (issueToUpdate) handleIssues(sub_group_by, group_by, issueToUpdate, EIssueActions.UPDATE); }; - const handleIssuePeekOverview = () => { + const handleIssuePeekOverview = (event: React.MouseEvent) => { const { query } = router; - - router.push({ - pathname: router.pathname, - query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, - }); + if (event.ctrlKey || event.metaKey) { + const issueUrl = `/${issue.workspace_detail.slug}/projects/${issue.project_detail.id}/issues/${issue?.id}`; + window.open(issueUrl, "_blank"); // Open link in a new tab + } else { + router.push({ + pathname: router.pathname, + query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, + }); + } }; return ( - <> +
{displayProperties && displayProperties?.key && ( -
-
+
+
{issue.project_detail.identifier}-{issue.sequence_id}
@@ -70,9 +91,7 @@ const KanbanIssueDetailsBlock: React.FC = (props) => {
)} -
- {issue.name} -
+
{issue.name}
= (props) => { isReadOnly={isReadOnly} />
- +
); }; @@ -132,22 +151,18 @@ export const KanbanIssueBlock: React.FC = (props) => { {issue.tempId !== undefined && (
)} -
- -
+
)} diff --git a/web/components/issues/issue-layouts/list/block.tsx b/web/components/issues/issue-layouts/list/block.tsx index 0667a7fa9..562f599ab 100644 --- a/web/components/issues/issue-layouts/list/block.tsx +++ b/web/components/issues/issue-layouts/list/block.tsx @@ -25,20 +25,27 @@ export const IssueBlock: React.FC = (props) => { handleIssues(issueToUpdate, EIssueActions.UPDATE); }; - const handleIssuePeekOverview = () => { + const handleIssuePeekOverview = (event: React.MouseEvent) => { const { query } = router; - - router.push({ - pathname: router.pathname, - query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, - }); + if (event.ctrlKey || event.metaKey) { + const issueUrl = `/${issue.workspace_detail.slug}/projects/${issue.project_detail.id}/issues/${issue?.id}`; + window.open(issueUrl, "_blank"); // Open link in a new tab + } else { + router.push({ + pathname: router.pathname, + query: { ...query, peekIssueId: issue?.id, peekProjectId: issue?.project }, + }); + } }; const canEditIssueProperties = canEditProperties(issue.project); return ( <> -
+ ); }; diff --git a/web/components/issues/issue-layouts/properties/assignee.tsx b/web/components/issues/issue-layouts/properties/assignee.tsx index acebed498..01dec9b83 100644 --- a/web/components/issues/issue-layouts/properties/assignee.tsx +++ b/web/components/issues/issue-layouts/properties/assignee.tsx @@ -142,7 +142,10 @@ export const IssuePropertyAssignee: React.FC = observer( className={`flex w-full items-center justify-between gap-1 text-xs ${ disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer" } ${buttonClassName}`} - onClick={() => (!projectId || !_members[projectId]) && getProjectMembers()} + onClick={(e) => { + e.stopPropagation(); + (!projectId || !_members[projectId]) && getProjectMembers(); + }} > {label} {!hideDropdownArrow && !disabled &&