[WEB-905] chore: issue peek overview and kanban layout improvement (#4135)

* chore: peek overview and kanban card improvement

* chore: peek overview improvement
This commit is contained in:
Anmol Singh Bhatia 2024-04-08 18:38:05 +05:30 committed by GitHub
parent fd2cacb0cd
commit 986f81e3ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 63 additions and 14 deletions

View File

@ -41,6 +41,7 @@ export const CalendarIssueBlock: React.FC<Props> = observer((props) => {
issue &&
issue.project_id &&
issue.id &&
peekIssue?.issueId !== issue.id &&
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
useOutsideClickDetector(menuActionRef, () => setIsMenuActive(false));
@ -64,6 +65,7 @@ export const CalendarIssueBlock: React.FC<Props> = observer((props) => {
return (
<ControlLink
id={`issue-${issue.id}`}
href={`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`}
target="_blank"
onClick={() => handleIssuePeekOverview(issue)}

View File

@ -20,6 +20,7 @@ export const IssueGanttBlock: React.FC<Props> = observer((props) => {
const { getProjectStates } = useProjectState();
const {
issue: { getIssueById },
peekIssue,
setPeekIssue,
} = useIssueDetail();
// derived values
@ -31,11 +32,13 @@ export const IssueGanttBlock: React.FC<Props> = observer((props) => {
workspaceSlug &&
issueDetails &&
!issueDetails.tempId &&
peekIssue?.issueId !== issueDetails.id &&
setPeekIssue({ workspaceSlug, projectId: issueDetails.project_id, issueId: issueDetails.id });
const { isMobile } = usePlatformOS();
return (
<div
id={`issue-${issueId}`}
className="relative flex h-full w-full cursor-pointer items-center rounded"
style={{
backgroundColor: stateDetails?.color,

View File

@ -47,13 +47,14 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
const {
router: { workspaceSlug },
} = useApplication();
const { setPeekIssue } = useIssueDetail();
const { peekIssue, setPeekIssue } = useIssueDetail();
const handleIssuePeekOverview = (issue: TIssue) =>
workspaceSlug &&
issue &&
issue.project_id &&
issue.id &&
peekIssue?.issueId !== issue.id &&
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
return (
@ -69,16 +70,17 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
{issue?.is_draft ? (
<Tooltip tooltipContent={issue.name} isMobile={isMobile}>
<span>{issue.name}</span>
<span className="pb-1.5">{issue.name}</span>
</Tooltip>
) : (
<ControlLink
id={`issue-${issue.id}`}
href={`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
issue.id
}`}
target="_blank"
onClick={() => handleIssuePeekOverview(issue)}
className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100"
className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100 pb-1.5"
disabled={!!issue?.tempId}
>
<Tooltip tooltipContent={issue.name} isMobile={isMobile}>
@ -138,7 +140,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = memo((props) => {
>
<div
className={cn(
"rounded border-[0.5px] w-full border-custom-border-200 bg-custom-background-100 text-sm transition-all hover:border-custom-border-400",
"rounded border-[0.5px] outline-[0.5px] outline-transparent w-full border-custom-border-200 bg-custom-background-100 text-sm transition-all hover:border-custom-border-400",
{ "hover:cursor-grab": !isDragDisabled },
{ "border-custom-primary-100": snapshot.isDragging },
{ "border border-custom-primary-70 hover:border-custom-primary-70": peekIssueId === issue.id }

View File

@ -34,6 +34,7 @@ export const IssueBlock: React.FC<IssueBlockProps> = observer((props: IssueBlock
issue &&
issue.project_id &&
issue.id &&
peekIssue?.issueId !== issue.id &&
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
const issue = issuesMap[issueId];
@ -71,6 +72,7 @@ export const IssueBlock: React.FC<IssueBlockProps> = observer((props: IssueBlock
</Tooltip>
) : (
<ControlLink
id={`issue-${issue.id}`}
href={`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
issue.id
}`}

View File

@ -154,10 +154,13 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
const [isMenuActive, setIsMenuActive] = useState(false);
const menuActionRef = useRef<HTMLDivElement | null>(null);
const handleIssuePeekOverview = (issue: TIssue) => {
if (workspaceSlug && issue && issue.project_id && issue.id)
setPeekIssue({ workspaceSlug: workspaceSlug.toString(), projectId: issue.project_id, issueId: issue.id });
};
const handleIssuePeekOverview = (issue: TIssue) =>
workspaceSlug &&
issue &&
issue.project_id &&
issue.id &&
peekIssue?.issueId !== issue.id &&
setPeekIssue({ workspaceSlug: workspaceSlug.toString(), projectId: issue.project_id, issueId: issue.id });
const { subIssues: subIssuesStore, issue } = useIssueDetail();
@ -240,6 +243,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
</div>
</WithDisplayPropertiesHOC>
<ControlLink
id={`issue-${issueId}`}
href={`/${workspaceSlug}/projects/${issueDetail.project_id}/issues/${issueId}`}
target="_blank"
onClick={() => handleIssuePeekOverview(issueDetail)}

View File

@ -16,7 +16,7 @@ import {
// hooks
import { useIssueDetail, useUser } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import usePeekOverviewOutsideClickDetector from "@/hooks/use-peek-overview-outside-click";
// store hooks
import { IssueActivity } from "../issue-detail/issue-activity";
import { SubIssuesRoot } from "../sub-issues";
@ -55,11 +55,15 @@ export const IssueView: FC<IIssueView> = observer((props) => {
setPeekIssue(undefined);
};
useOutsideClickDetector(issuePeekOverviewRef, () => {
if (!isAnyModalOpen) {
removeRoutePeekId();
}
});
usePeekOverviewOutsideClickDetector(
issuePeekOverviewRef,
() => {
if (!isAnyModalOpen) {
removeRoutePeekId();
}
},
issueId
);
const handleKeyDown = () => {
const slashCommandDropdownElement = document.querySelector("#slash-command");
const dropdownElement = document.activeElement?.tagName === "INPUT";

View File

@ -42,6 +42,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
} = props;
const {
peekIssue,
setPeekIssue,
issue: { getIssueById },
subIssues: { subIssueHelpersByIssueId, setSubIssueHelpers },
@ -64,6 +65,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
issue &&
issue.project_id &&
issue.id &&
peekIssue?.issueId !== issue.id &&
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
if (!issue) return <></>;
@ -117,6 +119,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
</div>
<ControlLink
id={`issue-${issue.id}`}
href={`/${workspaceSlug}/projects/${issue.project_id}/issues/${issue.id}`}
target="_blank"
onClick={() => handleIssuePeekOverview(issue)}

View File

@ -0,0 +1,29 @@
import React, { useEffect } from "react";
const usePeekOverviewOutsideClickDetector = (
ref: React.RefObject<HTMLElement>,
callback: () => void,
issueId: string
) => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
let targetElement = event.target as HTMLElement | null;
while (targetElement) {
if (targetElement.id === `issue-${issueId}`) {
return;
}
targetElement = targetElement.parentElement;
}
callback();
}
};
useEffect(() => {
document.addEventListener("mousedown", handleClick);
return () => {
document.removeEventListener("mousedown", handleClick);
};
});
};
export default usePeekOverviewOutsideClickDetector;